wifi_supplicant: deprecate entropy.bin am: bef8d2a2c6 am: 67b21a86fe
am: 0ed1e9b96c
Change-Id: Ifdb4501626989424da51d32baa49278cc75ae55a
diff --git a/libwifi_hal/wifi_hal_common.cpp b/libwifi_hal/wifi_hal_common.cpp
index 04e5925..413daf7 100644
--- a/libwifi_hal/wifi_hal_common.cpp
+++ b/libwifi_hal/wifi_hal_common.cpp
@@ -23,6 +23,7 @@
#include <android-base/logging.h>
#include <cutils/misc.h>
#include <cutils/properties.h>
+#include <sys/syscall.h>
extern "C" int init_module(void *, unsigned long, const char *);
extern "C" int delete_module(const char *, unsigned int);
@@ -51,16 +52,21 @@
#endif
static int insmod(const char *filename, const char *args) {
- void *module;
- unsigned int size;
int ret;
+ int fd;
- module = load_file(filename, &size);
- if (!module) return -1;
+ fd = TEMP_FAILURE_RETRY(open(filename, O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
+ if (fd < 0) {
+ PLOG(ERROR) << "Failed to open " << filename;
+ return -1;
+ }
- ret = init_module(module, size, args);
+ ret = syscall(__NR_finit_module, fd, args, 0);
- free(module);
+ close(fd);
+ if (ret < 0) {
+ PLOG(ERROR) << "finit_module return: " << ret;
+ }
return ret;
}
diff --git a/service/Android.mk b/service/Android.mk
index 5b539e5..7b3b115 100644
--- a/service/Android.mk
+++ b/service/Android.mk
@@ -65,7 +65,9 @@
android.hardware.wifi-V1.0-java \
android.hardware.wifi-V1.1-java \
android.hardware.wifi.supplicant-V1.0-java
-LOCAL_REQUIRED_MODULES := services
+LOCAL_REQUIRED_MODULES := \
+ services \
+ libwifi-service
LOCAL_MODULE_TAGS :=
LOCAL_MODULE := wifi-service
LOCAL_INIT_RC := wifi-events.rc
diff --git a/service/java/com/android/server/wifi/HalDeviceManager.java b/service/java/com/android/server/wifi/HalDeviceManager.java
index d6009c7..ffc7113 100644
--- a/service/java/com/android/server/wifi/HalDeviceManager.java
+++ b/service/java/com/android/server/wifi/HalDeviceManager.java
@@ -16,6 +16,8 @@
package com.android.server.wifi;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.hardware.wifi.V1_0.IWifi;
import android.hardware.wifi.V1_0.IWifiApIface;
import android.hardware.wifi.V1_0.IWifiChip;
@@ -34,10 +36,9 @@
import android.hidl.manager.V1_0.IServiceNotification;
import android.os.Handler;
import android.os.HwRemoteBinder;
-import android.os.Looper;
-import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
+import android.util.LongSparseArray;
import android.util.MutableBoolean;
import android.util.MutableInt;
import android.util.SparseArray;
@@ -70,8 +71,12 @@
@VisibleForTesting
public static final String HAL_INSTANCE_NAME = "default";
+ private final Clock mClock;
+
// public API
- public HalDeviceManager() {
+ public HalDeviceManager(Clock clock) {
+ mClock = clock;
+
mInterfaceAvailableForRequestListeners.put(IfaceType.STA, new HashSet<>());
mInterfaceAvailableForRequestListeners.put(IfaceType.AP, new HashSet<>());
mInterfaceAvailableForRequestListeners.put(IfaceType.P2P, new HashSet<>());
@@ -98,12 +103,14 @@
* single copy kept.
*
* @param listener ManagerStatusListener listener object.
- * @param looper Looper on which to dispatch listener. Null implies current looper.
+ * @param handler Handler on which to dispatch listener. Null implies the listener will be
+ * invoked synchronously from the context of the client which triggered the
+ * state change.
*/
- public void registerStatusListener(ManagerStatusListener listener, Looper looper) {
+ public void registerStatusListener(@NonNull ManagerStatusListener listener,
+ @Nullable Handler handler) {
synchronized (mLock) {
- if (!mManagerStatusListeners.add(new ManagerStatusListenerProxy(listener,
- looper == null ? Looper.myLooper() : looper))) {
+ if (!mManagerStatusListeners.add(new ManagerStatusListenerProxy(listener, handler))) {
Log.w(TAG, "registerStatusListener: duplicate registration ignored");
}
}
@@ -192,37 +199,38 @@
* @param destroyedListener Optional (nullable) listener to call when the allocated interface
* is removed. Will only be registered and used if an interface is
* created successfully.
- * @param looper The looper on which to dispatch the listener. A null value indicates the
- * current thread.
+ * @param handler Handler on which to dispatch listener. Null implies the listener will be
+ * invoked synchronously from the context of the client which triggered the
+ * iface destruction.
* @return A newly created interface - or null if the interface could not be created.
*/
- public IWifiStaIface createStaIface(InterfaceDestroyedListener destroyedListener,
- Looper looper) {
- return (IWifiStaIface) createIface(IfaceType.STA, destroyedListener, looper);
+ public IWifiStaIface createStaIface(@Nullable InterfaceDestroyedListener destroyedListener,
+ @Nullable Handler handler) {
+ return (IWifiStaIface) createIface(IfaceType.STA, destroyedListener, handler);
}
/**
* Create AP interface if possible (see createStaIface doc).
*/
- public IWifiApIface createApIface(InterfaceDestroyedListener destroyedListener,
- Looper looper) {
- return (IWifiApIface) createIface(IfaceType.AP, destroyedListener, looper);
+ public IWifiApIface createApIface(@Nullable InterfaceDestroyedListener destroyedListener,
+ @Nullable Handler handler) {
+ return (IWifiApIface) createIface(IfaceType.AP, destroyedListener, handler);
}
/**
* Create P2P interface if possible (see createStaIface doc).
*/
- public IWifiP2pIface createP2pIface(InterfaceDestroyedListener destroyedListener,
- Looper looper) {
- return (IWifiP2pIface) createIface(IfaceType.P2P, destroyedListener, looper);
+ public IWifiP2pIface createP2pIface(@Nullable InterfaceDestroyedListener destroyedListener,
+ @Nullable Handler handler) {
+ return (IWifiP2pIface) createIface(IfaceType.P2P, destroyedListener, handler);
}
/**
* Create NAN interface if possible (see createStaIface doc).
*/
- public IWifiNanIface createNanIface(InterfaceDestroyedListener destroyedListener,
- Looper looper) {
- return (IWifiNanIface) createIface(IfaceType.NAN, destroyedListener, looper);
+ public IWifiNanIface createNanIface(@Nullable InterfaceDestroyedListener destroyedListener,
+ @Nullable Handler handler) {
+ return (IWifiNanIface) createIface(IfaceType.NAN, destroyedListener, handler);
}
/**
@@ -263,11 +271,16 @@
* and false on failure. This listener is in addition to the one registered when the interface
* was created - allowing non-creators to monitor interface status.
*
- * Listener called-back on the specified looper - or on the current looper if a null is passed.
+ * @param destroyedListener Listener to call when the allocated interface is removed.
+ * Will only be registered and used if an interface is created
+ * successfully.
+ * @param handler Handler on which to dispatch listener. Null implies the listener will be
+ * invoked synchronously from the context of the client which triggered the
+ * iface destruction.
*/
public boolean registerDestroyedListener(IWifiIface iface,
- InterfaceDestroyedListener destroyedListener,
- Looper looper) {
+ @NonNull InterfaceDestroyedListener destroyedListener,
+ @Nullable Handler handler) {
String name = getName(iface);
if (DBG) Log.d(TAG, "registerDestroyedListener: iface(name)=" + name);
@@ -279,8 +292,7 @@
}
return cacheEntry.destroyedListeners.add(
- new InterfaceDestroyedListenerProxy(destroyedListener,
- looper == null ? Looper.myLooper() : looper));
+ new InterfaceDestroyedListenerProxy(name, destroyedListener, handler));
}
}
@@ -299,17 +311,17 @@
* @param ifaceType The interface type (IfaceType) to be monitored.
* @param listener Listener to call when an interface of the requested
* type could be created
- * @param looper The looper on which to dispatch the listener. A null value indicates the
- * current thread.
+ * @param handler Handler on which to dispatch listener. Null implies the listener will be
+ * invoked synchronously from the context of the client which triggered the
+ * mode change.
*/
public void registerInterfaceAvailableForRequestListener(int ifaceType,
- InterfaceAvailableForRequestListener listener, Looper looper) {
+ @NonNull InterfaceAvailableForRequestListener listener, @Nullable Handler handler) {
if (DBG) Log.d(TAG, "registerInterfaceAvailableForRequestListener: ifaceType=" + ifaceType);
synchronized (mLock) {
mInterfaceAvailableForRequestListeners.get(ifaceType).add(
- new InterfaceAvailableForRequestListenerProxy(listener,
- looper == null ? Looper.myLooper() : looper));
+ new InterfaceAvailableForRequestListenerProxy(listener, handler));
}
WifiChipInfo[] chipInfos = getAllChipInfo();
@@ -379,8 +391,10 @@
*
* Can be registered when the interface is requested with createXxxIface() - will
* only be valid if the interface creation was successful - i.e. a non-null was returned.
+ *
+ * @param ifaceName Name of the interface that was destroyed.
*/
- void onDestroyed();
+ void onDestroyed(@NonNull String ifaceName);
}
/**
@@ -396,43 +410,48 @@
}
/**
- * Creates a IWifiRttController corresponding to the input interface. A direct match to the
- * IWifiChip.createRttController() method.
+ * Creates a IWifiRttController. A direct match to the IWifiChip.createRttController() method.
*
* Returns the created IWifiRttController or a null on error.
*/
- public IWifiRttController createRttController(IWifiIface boundIface) {
- if (DBG) Log.d(TAG, "createRttController: boundIface(name)=" + getName(boundIface));
+ public IWifiRttController createRttController() {
+ if (DBG) Log.d(TAG, "createRttController");
synchronized (mLock) {
if (mWifi == null) {
- Log.e(TAG, "createRttController: null IWifi -- boundIface(name)="
- + getName(boundIface));
+ Log.e(TAG, "createRttController: null IWifi");
return null;
}
- IWifiChip chip = getChip(boundIface);
- if (chip == null) {
- Log.e(TAG, "createRttController: null IWifiChip -- boundIface(name)="
- + getName(boundIface));
+ WifiChipInfo[] chipInfos = getAllChipInfo();
+ if (chipInfos == null) {
+ Log.e(TAG, "createRttController: no chip info found");
+ stopWifi(); // major error: shutting down
return null;
}
- Mutable<IWifiRttController> rttResp = new Mutable<>();
- try {
- chip.createRttController(boundIface,
- (WifiStatus status, IWifiRttController rtt) -> {
- if (status.code == WifiStatusCode.SUCCESS) {
- rttResp.value = rtt;
- } else {
- Log.e(TAG, "IWifiChip.createRttController failed: " + statusString(
- status));
- }
- });
- } catch (RemoteException e) {
- Log.e(TAG, "IWifiChip.createRttController exception: " + e);
+ for (WifiChipInfo chipInfo : chipInfos) {
+ Mutable<IWifiRttController> rttResp = new Mutable<>();
+ try {
+ chipInfo.chip.createRttController(null,
+ (WifiStatus status, IWifiRttController rtt) -> {
+ if (status.code == WifiStatusCode.SUCCESS) {
+ rttResp.value = rtt;
+ } else {
+ Log.e(TAG,
+ "IWifiChip.createRttController failed: " + statusString(
+ status));
+ }
+ });
+ } catch (RemoteException e) {
+ Log.e(TAG, "IWifiChip.createRttController exception: " + e);
+ }
+ if (rttResp.value != null) {
+ return rttResp.value;
+ }
}
- return rttResp.value;
+ Log.e(TAG, "createRttController: not available from any of the chips");
+ return null;
}
}
@@ -469,12 +488,14 @@
public String name;
public int type;
public Set<InterfaceDestroyedListenerProxy> destroyedListeners = new HashSet<>();
+ public long creationTime;
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("{name=").append(name).append(", type=").append(type)
.append(", destroyedListeners.size()=").append(destroyedListeners.size())
+ .append(", creationTime=").append(creationTime)
.append("}");
return sb.toString();
}
@@ -1202,9 +1223,8 @@
private class ManagerStatusListenerProxy extends
ListenerProxy<ManagerStatusListener> {
- ManagerStatusListenerProxy(ManagerStatusListener statusListener,
- Looper looper) {
- super(statusListener, looper, "ManagerStatusListenerProxy");
+ ManagerStatusListenerProxy(ManagerStatusListener statusListener, Handler handler) {
+ super(statusListener, handler, "ManagerStatusListenerProxy");
}
@Override
@@ -1265,7 +1285,7 @@
}
private IWifiIface createIface(int ifaceType, InterfaceDestroyedListener destroyedListener,
- Looper looper) {
+ Handler handler) {
if (DBG) Log.d(TAG, "createIface: ifaceType=" + ifaceType);
synchronized (mLock) {
@@ -1283,7 +1303,7 @@
}
IWifiIface iface = createIfaceIfPossible(chipInfos, ifaceType, destroyedListener,
- looper);
+ handler);
if (iface != null) { // means that some configuration has changed
if (!dispatchAvailableForRequestListeners()) {
return null; // catastrophic failure - shut down
@@ -1295,7 +1315,7 @@
}
private IWifiIface createIfaceIfPossible(WifiChipInfo[] chipInfos, int ifaceType,
- InterfaceDestroyedListener destroyedListener, Looper looper) {
+ InterfaceDestroyedListener destroyedListener, Handler handler) {
if (DBG) {
Log.d(TAG, "createIfaceIfPossible: chipInfos=" + Arrays.deepToString(chipInfos)
+ ", ifaceType=" + ifaceType);
@@ -1336,9 +1356,10 @@
cacheEntry.type = ifaceType;
if (destroyedListener != null) {
cacheEntry.destroyedListeners.add(
- new InterfaceDestroyedListenerProxy(destroyedListener,
- looper == null ? Looper.myLooper() : looper));
+ new InterfaceDestroyedListenerProxy(
+ cacheEntry.name, destroyedListener, handler));
}
+ cacheEntry.creationTime = mClock.getUptimeSinceBootMillis();
if (DBG) Log.d(TAG, "createIfaceIfPossible: added cacheEntry=" + cacheEntry);
mInterfaceInfoCache.put(cacheEntry.name, cacheEntry);
@@ -1463,7 +1484,8 @@
if (isChipModeChangeProposed) {
for (int type: IFACE_TYPES_BY_PRIORITY) {
if (chipInfo.ifaces[type].length != 0) {
- if (!allowedToDeleteIfaceTypeForRequestedType(type, ifaceType)) {
+ if (!allowedToDeleteIfaceTypeForRequestedType(type, ifaceType,
+ chipInfo.ifaces[ifaceType].length != 0)) {
if (DBG) {
Log.d(TAG, "Couldn't delete existing type " + type
+ " interfaces for requested type");
@@ -1493,17 +1515,17 @@
}
if (tooManyInterfaces > 0) { // may need to delete some
- if (!allowedToDeleteIfaceTypeForRequestedType(type, ifaceType)) {
+ if (!allowedToDeleteIfaceTypeForRequestedType(type, ifaceType,
+ chipInfo.ifaces[ifaceType].length != 0)) {
if (DBG) {
Log.d(TAG, "Would need to delete some higher priority interfaces");
}
return null;
}
- // arbitrarily pick the first interfaces to delete
- for (int i = 0; i < tooManyInterfaces; ++i) {
- interfacesToBeRemovedFirst.add(chipInfo.ifaces[type][i]);
- }
+ // delete the most recently created interfaces
+ interfacesToBeRemovedFirst = selectInterfacesToDelete(tooManyInterfaces,
+ chipInfo.ifaces[type]);
}
}
@@ -1571,14 +1593,20 @@
* interface type.
*
* Rules:
- * 1. Request for AP or STA will destroy any other interface (except see #4)
+ * 1. Request for AP or STA will destroy any other interface (except see #4 and #5)
* 2. Request for P2P will destroy NAN-only
* 3. Request for NAN will not destroy any interface
* --
* 4. No interface will be destroyed for a requested interface of the same type
+ * 5. No interface will be destroyed if one of the requested interfaces already exists
*/
private boolean allowedToDeleteIfaceTypeForRequestedType(int existingIfaceType,
- int requestedIfaceType) {
+ int requestedIfaceType, boolean requestedIfaceTypeAlreadyExists) {
+ // rule 5
+ if (requestedIfaceTypeAlreadyExists) {
+ return false;
+ }
+
// rule 4
if (existingIfaceType == requestedIfaceType) {
return false;
@@ -1599,6 +1627,46 @@
}
/**
+ * Selects the interfaces to delete.
+ *
+ * Rule: select the most recently created interfaces in order.
+ *
+ * @param excessInterfaces Number of interfaces which need to be selected.
+ * @param interfaces Array of interfaces.
+ */
+ private List<WifiIfaceInfo> selectInterfacesToDelete(int excessInterfaces,
+ WifiIfaceInfo[] interfaces) {
+ if (DBG) {
+ Log.d(TAG, "selectInterfacesToDelete: excessInterfaces=" + excessInterfaces
+ + ", interfaces=" + Arrays.toString(interfaces));
+ }
+
+ boolean lookupError = false;
+ LongSparseArray<WifiIfaceInfo> orderedList = new LongSparseArray(interfaces.length);
+ for (WifiIfaceInfo info : interfaces) {
+ InterfaceCacheEntry cacheEntry = mInterfaceInfoCache.get(info.name);
+ if (cacheEntry == null) {
+ Log.e(TAG,
+ "selectInterfacesToDelete: can't find cache entry with name=" + info.name);
+ lookupError = true;
+ break;
+ }
+ orderedList.append(cacheEntry.creationTime, info);
+ }
+
+ if (lookupError) {
+ Log.e(TAG, "selectInterfacesToDelete: falling back to arbitary selection");
+ return Arrays.asList(Arrays.copyOf(interfaces, excessInterfaces));
+ } else {
+ List<WifiIfaceInfo> result = new ArrayList<>(excessInterfaces);
+ for (int i = 0; i < excessInterfaces; ++i) {
+ result.add(orderedList.valueAt(orderedList.size() - i - 1));
+ }
+ return result;
+ }
+ }
+
+ /**
* Performs chip reconfiguration per the input:
* - Removes the specified interfaces
* - Reconfigures the chip to the new chip mode (if necessary)
@@ -1841,8 +1909,6 @@
}
private abstract class ListenerProxy<LISTENER> {
- private static final int LISTENER_TRIGGERED = 0;
-
protected LISTENER mListener;
private Handler mHandler;
@@ -1859,50 +1925,44 @@
}
void trigger() {
- mHandler.sendMessage(mHandler.obtainMessage(LISTENER_TRIGGERED));
+ if (mHandler != null) {
+ mHandler.post(() -> {
+ action();
+ });
+ } else {
+ action();
+ }
}
protected abstract void action();
- ListenerProxy(LISTENER listener, Looper looper, String tag) {
+ ListenerProxy(LISTENER listener, Handler handler, String tag) {
mListener = listener;
- mHandler = new Handler(looper) {
- @Override
- public void handleMessage(Message msg) {
- if (DBG) {
- Log.d(tag, "ListenerProxy.handleMessage: what=" + msg.what);
- }
- switch (msg.what) {
- case LISTENER_TRIGGERED:
- action();
- break;
- default:
- Log.e(tag, "ListenerProxy.handleMessage: unknown message what="
- + msg.what);
- }
- }
- };
+ mHandler = handler;
}
}
private class InterfaceDestroyedListenerProxy extends
ListenerProxy<InterfaceDestroyedListener> {
- InterfaceDestroyedListenerProxy(InterfaceDestroyedListener destroyedListener,
- Looper looper) {
- super(destroyedListener, looper, "InterfaceDestroyedListenerProxy");
+ private final String mIfaceName;
+ InterfaceDestroyedListenerProxy(@NonNull String ifaceName,
+ InterfaceDestroyedListener destroyedListener,
+ Handler handler) {
+ super(destroyedListener, handler, "InterfaceDestroyedListenerProxy");
+ mIfaceName = ifaceName;
}
@Override
protected void action() {
- mListener.onDestroyed();
+ mListener.onDestroyed(mIfaceName);
}
}
private class InterfaceAvailableForRequestListenerProxy extends
ListenerProxy<InterfaceAvailableForRequestListener> {
InterfaceAvailableForRequestListenerProxy(
- InterfaceAvailableForRequestListener destroyedListener, Looper looper) {
- super(destroyedListener, looper, "InterfaceAvailableForRequestListenerProxy");
+ InterfaceAvailableForRequestListener destroyedListener, Handler handler) {
+ super(destroyedListener, handler, "InterfaceAvailableForRequestListenerProxy");
}
@Override
diff --git a/service/java/com/android/server/wifi/SoftApManager.java b/service/java/com/android/server/wifi/SoftApManager.java
index d4a1ea5..429e3c3 100644
--- a/service/java/com/android/server/wifi/SoftApManager.java
+++ b/service/java/com/android/server/wifi/SoftApManager.java
@@ -20,23 +20,28 @@
import static com.android.server.wifi.util.ApConfigUtil.ERROR_NO_CHANNEL;
import static com.android.server.wifi.util.ApConfigUtil.SUCCESS;
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.Intent;
import android.net.InterfaceConfiguration;
import android.net.wifi.IApInterface;
import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.net.wifi.WifiManager;
import android.os.INetworkManagementService;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
+import android.os.UserHandle;
+import android.text.TextUtils;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
import com.android.server.net.BaseNetworkObserver;
+import com.android.server.wifi.WifiNative.SoftApListener;
import com.android.server.wifi.util.ApConfigUtil;
-import java.nio.charset.StandardCharsets;
import java.util.Locale;
/**
@@ -46,6 +51,8 @@
public class SoftApManager implements ActiveModeManager {
private static final String TAG = "SoftApManager";
+ private final Context mContext;
+
private final WifiNative mWifiNative;
private final String mCountryCode;
@@ -55,14 +62,27 @@
private final Listener mListener;
private final IApInterface mApInterface;
+ private final String mApInterfaceName;
private final INetworkManagementService mNwService;
private final WifiApConfigStore mWifiApConfigStore;
private final WifiMetrics mWifiMetrics;
+ private final int mMode;
private WifiConfiguration mApConfig;
+ private int mNumAssociatedStations = 0;
+
+ private final SoftApListener mSoftApListener = new SoftApListener() {
+ @Override
+ public void onNumAssociatedStationsChanged(int numStations) {
+ mStateMachine.sendMessage(
+ SoftApStateMachine.CMD_NUM_ASSOCIATED_STATIONS_CHANGED, numStations);
+ }
+ };
+
+
/**
* Listener for soft AP state changes.
*/
@@ -75,23 +95,29 @@
void onStateChanged(int state, int failureReason);
}
- public SoftApManager(Looper looper,
+ public SoftApManager(Context context,
+ Looper looper,
WifiNative wifiNative,
String countryCode,
Listener listener,
- IApInterface apInterface,
+ @NonNull IApInterface apInterface,
+ @NonNull String ifaceName,
INetworkManagementService nms,
WifiApConfigStore wifiApConfigStore,
- WifiConfiguration config,
+ @NonNull SoftApModeConfiguration apConfig,
WifiMetrics wifiMetrics) {
mStateMachine = new SoftApStateMachine(looper);
+ mContext = context;
mWifiNative = wifiNative;
mCountryCode = countryCode;
mListener = listener;
mApInterface = apInterface;
+ mApInterfaceName = ifaceName;
mNwService = nms;
mWifiApConfigStore = wifiApConfigStore;
+ mMode = apConfig.getTargetMode();
+ WifiConfiguration config = apConfig.getWifiConfiguration();
if (config == null) {
mApConfig = mWifiApConfigStore.getApConfiguration();
} else {
@@ -115,14 +141,52 @@
}
/**
+ * Get number of stations associated with this soft AP
+ */
+ @VisibleForTesting
+ public int getNumAssociatedStations() {
+ return mNumAssociatedStations;
+ }
+
+ /**
+ * Set number of stations associated with this soft AP
+ * @param numStations Number of connected stations
+ */
+ private void setNumAssociatedStations(int numStations) {
+ if (mNumAssociatedStations == numStations) {
+ return;
+ }
+ mNumAssociatedStations = numStations;
+ Log.d(TAG, "Number of associated stations changed: " + mNumAssociatedStations);
+
+ // TODO:(b/63906412) send it up to settings.
+ mWifiMetrics.addSoftApNumAssociatedStationsChangedEvent(mNumAssociatedStations, mMode);
+ }
+
+ /**
* Update AP state.
- * @param state new AP state
+ * @param newState new AP state
+ * @param currentState current AP state
* @param reason Failure reason if the new AP state is in failure state
*/
- private void updateApState(int state, int reason) {
+ private void updateApState(int newState, int currentState, int reason) {
if (mListener != null) {
- mListener.onStateChanged(state, reason);
+ mListener.onStateChanged(newState, reason);
}
+
+ //send the AP state change broadcast
+ final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, newState);
+ intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, currentState);
+ if (newState == WifiManager.WIFI_AP_STATE_FAILED) {
+ //only set reason number when softAP start failed
+ intent.putExtra(WifiManager.EXTRA_WIFI_AP_FAILURE_REASON, reason);
+ }
+
+ intent.putExtra(WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME, mApInterfaceName);
+ intent.putExtra(WifiManager.EXTRA_WIFI_AP_MODE, mMode);
+ mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
/**
@@ -142,6 +206,7 @@
int result = ApConfigUtil.updateApChannelConfig(
mWifiNative, mCountryCode,
mWifiApConfigStore.getAllowed2GChannel(), localConfig);
+
if (result != SUCCESS) {
Log.e(TAG, "Failed to update AP band and channel");
return result;
@@ -158,71 +223,24 @@
return ERROR_GENERIC;
}
}
-
- int encryptionType = getIApInterfaceEncryptionType(localConfig);
-
if (localConfig.hiddenSSID) {
Log.d(TAG, "SoftAP is a hidden network");
}
-
- try {
- // Note that localConfig.SSID is intended to be either a hex string or "double quoted".
- // However, it seems that whatever is handing us these configurations does not obey
- // this convention.
- boolean success = mApInterface.writeHostapdConfig(
- localConfig.SSID.getBytes(StandardCharsets.UTF_8), localConfig.hiddenSSID,
- localConfig.apChannel, encryptionType,
- (localConfig.preSharedKey != null)
- ? localConfig.preSharedKey.getBytes(StandardCharsets.UTF_8)
- : new byte[0]);
- if (!success) {
- Log.e(TAG, "Failed to write hostapd configuration");
- return ERROR_GENERIC;
- }
-
- success = mApInterface.startHostapd();
- if (!success) {
- Log.e(TAG, "Failed to start hostapd.");
- return ERROR_GENERIC;
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Exception in starting soft AP: " + e);
+ if (!mWifiNative.startSoftAp(localConfig, mSoftApListener)) {
+ Log.e(TAG, "Soft AP start failed");
+ return ERROR_GENERIC;
}
-
Log.d(TAG, "Soft AP is started");
return SUCCESS;
}
- private static int getIApInterfaceEncryptionType(WifiConfiguration localConfig) {
- int encryptionType;
- switch (localConfig.getAuthType()) {
- case KeyMgmt.NONE:
- encryptionType = IApInterface.ENCRYPTION_TYPE_NONE;
- break;
- case KeyMgmt.WPA_PSK:
- encryptionType = IApInterface.ENCRYPTION_TYPE_WPA;
- break;
- case KeyMgmt.WPA2_PSK:
- encryptionType = IApInterface.ENCRYPTION_TYPE_WPA2;
- break;
- default:
- // We really shouldn't default to None, but this was how NetworkManagementService
- // used to do this.
- encryptionType = IApInterface.ENCRYPTION_TYPE_NONE;
- break;
- }
- return encryptionType;
- }
-
/**
* Teardown soft AP.
*/
private void stopSoftAp() {
- try {
- mApInterface.stopHostapd();
- } catch (RemoteException e) {
- Log.e(TAG, "Exception in stopping soft AP: " + e);
+ if (!mWifiNative.stopSoftAp()) {
+ Log.d(TAG, "Soft AP stop failed");
return;
}
Log.d(TAG, "Soft AP is stopped");
@@ -232,14 +250,16 @@
// Commands for the state machine.
public static final int CMD_START = 0;
public static final int CMD_STOP = 1;
- public static final int CMD_AP_INTERFACE_BINDER_DEATH = 2;
+ public static final int CMD_WIFICOND_BINDER_DEATH = 2;
public static final int CMD_INTERFACE_STATUS_CHANGED = 3;
+ public static final int CMD_NUM_ASSOCIATED_STATIONS_CHANGED = 4;
private final State mIdleState = new IdleState();
private final State mStartedState = new StartedState();
- private final StateMachineDeathRecipient mDeathRecipient =
- new StateMachineDeathRecipient(this, CMD_AP_INTERFACE_BINDER_DEATH);
+ private final WifiNative.WificondDeathEventHandler mWificondDeathRecipient = () -> {
+ sendMessage(CMD_WIFICOND_BINDER_DEATH);
+ };
private NetworkObserver mNetworkObserver;
@@ -272,7 +292,7 @@
private class IdleState extends State {
@Override
public void enter() {
- mDeathRecipient.unlinkToDeath();
+ mWifiNative.deregisterWificondDeathHandler();
unregisterObserver();
}
@@ -280,23 +300,36 @@
public boolean processMessage(Message message) {
switch (message.what) {
case CMD_START:
- updateApState(WifiManager.WIFI_AP_STATE_ENABLING, 0);
- if (!mDeathRecipient.linkToDeath(mApInterface.asBinder())) {
- mDeathRecipient.unlinkToDeath();
+ // first a sanity check on the interface name. If we failed to retrieve it,
+ // we are going to have a hard time setting up routing.
+ if (TextUtils.isEmpty(mApInterfaceName)) {
+ Log.e(TAG, "Not starting softap mode without an interface name.");
updateApState(WifiManager.WIFI_AP_STATE_FAILED,
+ WifiManager.WIFI_AP_STATE_DISABLED,
+ WifiManager.SAP_START_FAILURE_GENERAL);
+ mWifiMetrics.incrementSoftApStartResult(
+ false, WifiManager.SAP_START_FAILURE_GENERAL);
+ break;
+ }
+ updateApState(WifiManager.WIFI_AP_STATE_ENABLING,
+ WifiManager.WIFI_AP_STATE_DISABLED, 0);
+ setNumAssociatedStations(0);
+ if (!mWifiNative.registerWificondDeathHandler(mWificondDeathRecipient)) {
+ updateApState(WifiManager.WIFI_AP_STATE_FAILED,
+ WifiManager.WIFI_AP_STATE_ENABLING,
WifiManager.SAP_START_FAILURE_GENERAL);
mWifiMetrics.incrementSoftApStartResult(
false, WifiManager.SAP_START_FAILURE_GENERAL);
break;
}
-
try {
- mNetworkObserver = new NetworkObserver(mApInterface.getInterfaceName());
+ mNetworkObserver = new NetworkObserver(mApInterfaceName);
mNwService.registerObserver(mNetworkObserver);
} catch (RemoteException e) {
- mDeathRecipient.unlinkToDeath();
+ mWifiNative.deregisterWificondDeathHandler();
unregisterObserver();
updateApState(WifiManager.WIFI_AP_STATE_FAILED,
+ WifiManager.WIFI_AP_STATE_ENABLING,
WifiManager.SAP_START_FAILURE_GENERAL);
mWifiMetrics.incrementSoftApStartResult(
false, WifiManager.SAP_START_FAILURE_GENERAL);
@@ -309,9 +342,11 @@
if (result == ERROR_NO_CHANNEL) {
failureReason = WifiManager.SAP_START_FAILURE_NO_CHANNEL;
}
- mDeathRecipient.unlinkToDeath();
+ mWifiNative.deregisterWificondDeathHandler();
unregisterObserver();
- updateApState(WifiManager.WIFI_AP_STATE_FAILED, failureReason);
+ updateApState(WifiManager.WIFI_AP_STATE_FAILED,
+ WifiManager.WIFI_AP_STATE_ENABLING,
+ failureReason);
mWifiMetrics.incrementSoftApStartResult(false, failureReason);
break;
}
@@ -347,11 +382,15 @@
mIfaceIsUp = isUp;
if (isUp) {
Log.d(TAG, "SoftAp is ready for use");
- updateApState(WifiManager.WIFI_AP_STATE_ENABLED, 0);
+ updateApState(WifiManager.WIFI_AP_STATE_ENABLED,
+ WifiManager.WIFI_AP_STATE_ENABLING, 0);
mWifiMetrics.incrementSoftApStartResult(true, 0);
} else {
// TODO: handle the case where the interface was up, but goes down
}
+
+ mWifiMetrics.addSoftApUpChangedEvent(isUp, mMode);
+ setNumAssociatedStations(0);
}
@Override
@@ -359,7 +398,7 @@
mIfaceIsUp = false;
InterfaceConfiguration config = null;
try {
- config = mNwService.getInterfaceConfig(mApInterface.getInterfaceName());
+ config = mNwService.getInterfaceConfig(mApInterfaceName);
} catch (RemoteException e) {
}
if (config != null) {
@@ -370,6 +409,13 @@
@Override
public boolean processMessage(Message message) {
switch (message.what) {
+ case CMD_NUM_ASSOCIATED_STATIONS_CHANGED:
+ if (message.arg1 < 0) {
+ Log.e(TAG, "Invalid number of associated stations: " + message.arg1);
+ break;
+ }
+ setNumAssociatedStations(message.arg1);
+ break;
case CMD_INTERFACE_STATUS_CHANGED:
if (message.obj != mNetworkObserver) {
// This is from some time before the most recent configuration.
@@ -381,17 +427,25 @@
case CMD_START:
// Already started, ignore this command.
break;
- case CMD_AP_INTERFACE_BINDER_DEATH:
+ case CMD_WIFICOND_BINDER_DEATH:
case CMD_STOP:
- updateApState(WifiManager.WIFI_AP_STATE_DISABLING, 0);
+ updateApState(WifiManager.WIFI_AP_STATE_DISABLING,
+ WifiManager.WIFI_AP_STATE_ENABLED, 0);
+ setNumAssociatedStations(0);
stopSoftAp();
- if (message.what == CMD_AP_INTERFACE_BINDER_DEATH) {
+ if (message.what == CMD_WIFICOND_BINDER_DEATH) {
updateApState(WifiManager.WIFI_AP_STATE_FAILED,
- WifiManager.SAP_START_FAILURE_GENERAL);
+ WifiManager.WIFI_AP_STATE_DISABLING,
+ WifiManager.SAP_START_FAILURE_GENERAL);
} else {
- updateApState(WifiManager.WIFI_AP_STATE_DISABLED, 0);
+ updateApState(WifiManager.WIFI_AP_STATE_DISABLED,
+ WifiManager.WIFI_AP_STATE_DISABLING, 0);
}
transitionTo(mIdleState);
+
+ // Need this here since we are exiting |Started| state and won't handle any
+ // future CMD_INTERFACE_STATUS_CHANGED events after this point
+ mWifiMetrics.addSoftApUpChangedEvent(false, mMode);
break;
default:
return NOT_HANDLED;
@@ -399,6 +453,5 @@
return HANDLED;
}
}
-
}
}
diff --git a/service/java/com/android/server/wifi/StateMachineDeathRecipient.java b/service/java/com/android/server/wifi/StateMachineDeathRecipient.java
deleted file mode 100644
index 64c4bee..0000000
--- a/service/java/com/android/server/wifi/StateMachineDeathRecipient.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wifi;
-
-import android.os.IBinder;
-import android.os.IBinder.DeathRecipient;
-import android.os.RemoteException;
-import com.android.internal.util.StateMachine;
-
-/**
- * Allows StateMachine instances to subscribe to binder death.
- *
- * @hide
- */
-public class StateMachineDeathRecipient implements DeathRecipient {
-
- private final StateMachine mStateMachine;
- private final int mDeathCommand;
- private IBinder mLinkedBinder;
-
- /**
- * Construct a StateMachineDeathRecipient.
- *
- * @param sm StateMachine instance to receive a message upon Binder death.
- * @param command message to send the state machine.
- */
- public StateMachineDeathRecipient(StateMachine sm, int command) {
- mStateMachine = sm;
- mDeathCommand = command;
- }
-
- /**
- * Listen for the death of a binder.
- *
- * This method will unlink from death notifications from any
- * previously linked IBinder instance.
- *
- * @param binder remote object to listen for death.
- * @return true iff we have successfully subscribed to death notifications of a live
- * IBinder instance.
- */
- public boolean linkToDeath(IBinder binder) {
- unlinkToDeath();
- try {
- binder.linkToDeath(this, 0);
- } catch (RemoteException e) {
- // The remote has already died.
- return false;
- }
- mLinkedBinder = binder;
- return true;
- }
-
- /**
- * Unlink from notifications from the last linked IBinder instance.
- */
- public void unlinkToDeath() {
- if (mLinkedBinder == null) {
- return;
- }
- mLinkedBinder.unlinkToDeath(this, 0);
- mLinkedBinder = null;
- }
-
- /**
- * Called by the binder subsystem upon remote object death.
- */
- @Override
- public void binderDied() {
- mStateMachine.sendMessage(mDeathCommand);
- }
-}
\ No newline at end of file
diff --git a/service/java/com/android/server/wifi/SupplicantStaIfaceHal.java b/service/java/com/android/server/wifi/SupplicantStaIfaceHal.java
index d2182fc..664b052 100644
--- a/service/java/com/android/server/wifi/SupplicantStaIfaceHal.java
+++ b/service/java/com/android/server/wifi/SupplicantStaIfaceHal.java
@@ -53,6 +53,7 @@
import android.util.Pair;
import android.util.SparseArray;
+import com.android.server.wifi.WifiNative.SupplicantDeathEventHandler;
import com.android.server.wifi.hotspot2.AnqpEvent;
import com.android.server.wifi.hotspot2.IconEvent;
import com.android.server.wifi.hotspot2.WnmData;
@@ -69,6 +70,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -96,8 +98,15 @@
// Supplicant HAL interface objects
private IServiceManager mIServiceManager = null;
private ISupplicant mISupplicant;
- private ISupplicantStaIface mISupplicantStaIface;
- private ISupplicantStaIfaceCallback mISupplicantStaIfaceCallback;
+ private HashMap<String, ISupplicantStaIface> mISupplicantStaIfaces = new HashMap<>();
+ private HashMap<String, ISupplicantStaIfaceCallback> mISupplicantStaIfaceCallbacks =
+ new HashMap<>();
+ private HashMap<String, SupplicantStaNetworkHal> mCurrentNetworkRemoteHandles = new HashMap<>();
+ private HashMap<String, WifiConfiguration> mCurrentNetworkLocalConfigs = new HashMap<>();
+ private SupplicantDeathEventHandler mDeathEventHandler;
+ private final Context mContext;
+ private final WifiMonitor mWifiMonitor;
+
private final IServiceNotification mServiceNotificationCallback =
new IServiceNotification.Stub() {
public void onRegistration(String fqName, String name, boolean preexisting) {
@@ -106,11 +115,11 @@
Log.i(TAG, "IServiceNotification.onRegistration for: " + fqName
+ ", " + name + " preexisting=" + preexisting);
}
- if (!initSupplicantService() || !initSupplicantStaIface()) {
- Log.e(TAG, "initalizing ISupplicantIfaces failed.");
+ if (!initSupplicantService()) {
+ Log.e(TAG, "initalizing ISupplicant failed.");
supplicantServiceDiedHandler();
} else {
- Log.i(TAG, "Completed initialization of ISupplicant interfaces.");
+ Log.i(TAG, "Completed initialization of ISupplicant.");
}
}
}
@@ -131,16 +140,10 @@
}
};
- private String mIfaceName;
- private SupplicantStaNetworkHal mCurrentNetworkRemoteHandle;
- private WifiConfiguration mCurrentNetworkLocalConfig;
- private final Context mContext;
- private final WifiMonitor mWifiMonitor;
public SupplicantStaIfaceHal(Context context, WifiMonitor monitor) {
mContext = context;
mWifiMonitor = monitor;
- mISupplicantStaIfaceCallback = new SupplicantStaIfaceHalCallback();
}
/**
@@ -183,7 +186,7 @@
Log.i(TAG, "Registering ISupplicant service ready callback.");
}
mISupplicant = null;
- mISupplicantStaIface = null;
+ mISupplicantStaIfaces.clear();
if (mIServiceManager != null) {
// Already have an IServiceManager and serviceNotification registered, don't
// don't register another.
@@ -252,11 +255,11 @@
return true;
}
- private boolean linkToSupplicantStaIfaceDeath() {
+ private boolean linkToSupplicantStaIfaceDeath(ISupplicantStaIface iface) {
synchronized (mLock) {
- if (mISupplicantStaIface == null) return false;
+ if (iface == null) return false;
try {
- if (!mISupplicantStaIface.linkToDeath(mSupplicantDeathRecipient, 0)) {
+ if (!iface.linkToDeath(mSupplicantDeathRecipient, 0)) {
Log.wtf(TAG, "Error on linkToDeath on ISupplicantStaIface");
supplicantServiceDiedHandler();
return false;
@@ -269,16 +272,23 @@
}
}
- private int getCurrentNetworkId() {
+ private int getCurrentNetworkId(@NonNull String ifaceName) {
synchronized (mLock) {
- if (mCurrentNetworkLocalConfig == null) {
+ WifiConfiguration currentConfig = getCurrentNetworkLocalConfig(ifaceName);
+ if (currentConfig == null) {
return WifiConfiguration.INVALID_NETWORK_ID;
}
- return mCurrentNetworkLocalConfig.networkId;
+ return currentConfig.networkId;
}
}
- private boolean initSupplicantStaIface() {
+ /**
+ * Setup a STA interface for the specified iface name.
+ *
+ * @param ifaceName Name of the interface.
+ * @return true on success, false otherwise.
+ */
+ public boolean setupIface(@NonNull String ifaceName) {
synchronized (mLock) {
/** List all supplicant Ifaces */
final ArrayList<ISupplicant.IfaceInfo> supplicantIfaces = new ArrayList<>();
@@ -293,6 +303,7 @@
});
} catch (RemoteException e) {
Log.e(TAG, "ISupplicant.listInterfaces exception: " + e);
+ supplicantServiceDiedHandler(ifaceName);
return false;
}
if (supplicantIfaces.size() == 0) {
@@ -300,9 +311,8 @@
return false;
}
Mutable<ISupplicantIface> supplicantIface = new Mutable<>();
- Mutable<String> ifaceName = new Mutable<>();
for (ISupplicant.IfaceInfo ifaceInfo : supplicantIfaces) {
- if (ifaceInfo.type == IfaceType.STA) {
+ if (ifaceInfo.type == IfaceType.STA && ifaceName.equals(ifaceInfo.name)) {
try {
mISupplicant.getInterface(ifaceInfo,
(SupplicantStatus status, ISupplicantIface iface) -> {
@@ -314,33 +324,99 @@
});
} catch (RemoteException e) {
Log.e(TAG, "ISupplicant.getInterface exception: " + e);
+ supplicantServiceDiedHandler(ifaceName);
return false;
}
- ifaceName.value = ifaceInfo.name;
break;
}
}
if (supplicantIface.value == null) {
- Log.e(TAG, "initSupplicantStaIface got null iface");
+ Log.e(TAG, "setupSupplicantStaIface got null iface");
return false;
}
- mISupplicantStaIface = getStaIfaceMockable(supplicantIface.value);
- mIfaceName = ifaceName.value;
- if (!linkToSupplicantStaIfaceDeath()) {
+ ISupplicantStaIface iface = getStaIfaceMockable(supplicantIface.value);
+ if (!linkToSupplicantStaIfaceDeath(iface)) {
return false;
}
- if (!registerCallback(mISupplicantStaIfaceCallback)) {
+ ISupplicantStaIfaceCallback callback = new SupplicantStaIfaceHalCallback(ifaceName);
+ if (!registerCallback(iface, callback)) {
return false;
}
+ mISupplicantStaIfaces.put(ifaceName, iface);
+ mISupplicantStaIfaceCallbacks.put(ifaceName, callback);
return true;
}
}
+ /**
+ * Registers a death notification for supplicant.
+ * @return Returns true on success.
+ */
+ public boolean registerDeathHandler(@NonNull SupplicantDeathEventHandler handler) {
+ if (mDeathEventHandler != null) {
+ Log.e(TAG, "Death handler already present");
+ return false;
+ }
+ mDeathEventHandler = handler;
+ return true;
+ }
+
+ /**
+ * Deregisters a death notification for supplicant.
+ * @return Returns true on success.
+ */
+ public boolean deregisterDeathHandler() {
+ if (mDeathEventHandler == null) {
+ Log.e(TAG, "No Death handler present");
+ return false;
+ }
+ mDeathEventHandler = null;
+ return true;
+ }
+
+ /**
+ * Teardown a STA interface for the specified iface name.
+ *
+ * @param ifaceName Name of the interface.
+ * @return true on success, false otherwise.
+ */
+ public boolean teardownIface(@NonNull String ifaceName) {
+ synchronized (mLock) {
+ if (mISupplicantStaIfaces.remove(ifaceName) == null) {
+ return false;
+ }
+ mISupplicantStaIfaceCallbacks.remove(ifaceName);
+ // TODO(b/69162019): There are no HIDL calls to bring down interfaces
+ // from wpa_supplicant yet!
+ return true;
+ }
+ }
+
+ private void clearState() {
+ synchronized (mLock) {
+ mISupplicant = null;
+ mISupplicantStaIfaces.clear();
+ mCurrentNetworkLocalConfigs.clear();
+ mCurrentNetworkRemoteHandles.clear();
+ }
+ }
+
+ private void supplicantServiceDiedHandler(@NonNull String ifaceName) {
+ synchronized (mLock) {
+ mWifiMonitor.broadcastSupplicantDisconnectionEvent(ifaceName);
+ clearState();
+ }
+ }
+
private void supplicantServiceDiedHandler() {
synchronized (mLock) {
- mISupplicant = null;
- mISupplicantStaIface = null;
- mWifiMonitor.broadcastSupplicantDisconnectionEvent(mIfaceName);
+ if (mDeathEventHandler != null) {
+ mDeathEventHandler.onDeath();
+ }
+ for (String ifaceName : mISupplicantStaIfaces.keySet()) {
+ mWifiMonitor.broadcastSupplicantDisconnectionEvent(ifaceName);
+ }
+ clearState();
}
}
@@ -358,7 +434,7 @@
*/
public boolean isInitializationComplete() {
synchronized (mLock) {
- return mISupplicantStaIface != null;
+ return mISupplicant != null;
}
}
@@ -384,6 +460,27 @@
}
/**
+ * Helper method to look up the network object for the specified iface.
+ */
+ private ISupplicantStaIface getStaIface(@NonNull String ifaceName) {
+ return mISupplicantStaIfaces.get(ifaceName);
+ }
+
+ /**
+ * Helper method to look up the network object for the specified iface.
+ */
+ private SupplicantStaNetworkHal getCurrentNetworkRemoteHandle(@NonNull String ifaceName) {
+ return mCurrentNetworkRemoteHandles.get(ifaceName);
+ }
+
+ /**
+ * Helper method to look up the network config or the specified iface.
+ */
+ private WifiConfiguration getCurrentNetworkLocalConfig(@NonNull String ifaceName) {
+ return mCurrentNetworkLocalConfigs.get(ifaceName);
+ }
+
+ /**
* Add a network configuration to wpa_supplicant.
*
* @param config Config corresponding to the network.
@@ -391,14 +488,14 @@
* for the current network.
*/
private Pair<SupplicantStaNetworkHal, WifiConfiguration>
- addNetworkAndSaveConfig(WifiConfiguration config) {
+ addNetworkAndSaveConfig(@NonNull String ifaceName, WifiConfiguration config) {
synchronized (mLock) {
logi("addSupplicantStaNetwork via HIDL");
if (config == null) {
loge("Cannot add NULL network!");
return null;
}
- SupplicantStaNetworkHal network = addNetwork();
+ SupplicantStaNetworkHal network = addNetwork(ifaceName);
if (network == null) {
loge("Failed to add a network!");
return null;
@@ -411,7 +508,7 @@
}
if (!saveSuccess) {
loge("Failed to save variables for: " + config.configKey());
- if (!removeAllNetworks()) {
+ if (!removeAllNetworks(ifaceName)) {
loge("Failed to remove all networks on failure.");
}
return null;
@@ -427,32 +524,50 @@
* networks and saves |config|.
* 2. Select the new network in wpa_supplicant.
*
+ * @param ifaceName Name of the interface.
* @param config WifiConfiguration parameters for the provided network.
* @return {@code true} if it succeeds, {@code false} otherwise
*/
- public boolean connectToNetwork(@NonNull WifiConfiguration config) {
+ public boolean connectToNetwork(@NonNull String ifaceName, @NonNull WifiConfiguration config) {
synchronized (mLock) {
logd("connectToNetwork " + config.configKey());
- if (WifiConfigurationUtil.isSameNetwork(config, mCurrentNetworkLocalConfig)) {
- logd("Network is already saved, will not trigger remove and add operation.");
+ WifiConfiguration currentConfig = getCurrentNetworkLocalConfig(ifaceName);
+ if (WifiConfigurationUtil.isSameNetwork(config, currentConfig)) {
+ String networkSelectionBSSID = config.getNetworkSelectionStatus()
+ .getNetworkSelectionBSSID();
+ String networkSelectionBSSIDCurrent =
+ currentConfig.getNetworkSelectionStatus().getNetworkSelectionBSSID();
+ if (Objects.equals(networkSelectionBSSID, networkSelectionBSSIDCurrent)) {
+ logd("Network is already saved, will not trigger remove and add operation.");
+ } else {
+ logd("Network is already saved, but need to update BSSID.");
+ if (!setCurrentNetworkBssid(
+ ifaceName,
+ config.getNetworkSelectionStatus().getNetworkSelectionBSSID())) {
+ loge("Failed to set current network BSSID.");
+ return false;
+ }
+ mCurrentNetworkLocalConfigs.put(ifaceName, new WifiConfiguration(config));
+ }
} else {
- mCurrentNetworkRemoteHandle = null;
- mCurrentNetworkLocalConfig = null;
- if (!removeAllNetworks()) {
+ mCurrentNetworkRemoteHandles.remove(ifaceName);
+ mCurrentNetworkLocalConfigs.remove(ifaceName);
+ if (!removeAllNetworks(ifaceName)) {
loge("Failed to remove existing networks");
return false;
}
Pair<SupplicantStaNetworkHal, WifiConfiguration> pair =
- addNetworkAndSaveConfig(config);
+ addNetworkAndSaveConfig(ifaceName, config);
if (pair == null) {
loge("Failed to add/save network configuration: " + config.configKey());
return false;
}
- mCurrentNetworkRemoteHandle = pair.first;
- mCurrentNetworkLocalConfig = pair.second;
+ mCurrentNetworkRemoteHandles.put(ifaceName, pair.first);
+ mCurrentNetworkLocalConfigs.put(ifaceName, pair.second);
}
-
- if (!mCurrentNetworkRemoteHandle.select()) {
+ SupplicantStaNetworkHal networkHandle =
+ checkSupplicantStaNetworkAndLogFailure(ifaceName, "connectToNetwork");
+ if (networkHandle == null || !networkHandle.select()) {
loge("Failed to select network configuration: " + config.configKey());
return false;
}
@@ -469,23 +584,27 @@
* 2. Set the new bssid for the network in wpa_supplicant.
* 3. Trigger reassociate command to wpa_supplicant.
*
+ * @param ifaceName Name of the interface.
* @param config WifiConfiguration parameters for the provided network.
* @return {@code true} if it succeeds, {@code false} otherwise
*/
- public boolean roamToNetwork(WifiConfiguration config) {
+ public boolean roamToNetwork(@NonNull String ifaceName, WifiConfiguration config) {
synchronized (mLock) {
- if (getCurrentNetworkId() != config.networkId) {
+ if (getCurrentNetworkId(ifaceName) != config.networkId) {
Log.w(TAG, "Cannot roam to a different network, initiate new connection. "
- + "Current network ID: " + getCurrentNetworkId());
- return connectToNetwork(config);
+ + "Current network ID: " + getCurrentNetworkId(ifaceName));
+ return connectToNetwork(ifaceName, config);
}
String bssid = config.getNetworkSelectionStatus().getNetworkSelectionBSSID();
logd("roamToNetwork" + config.configKey() + " (bssid " + bssid + ")");
- if (!mCurrentNetworkRemoteHandle.setBssid(bssid)) {
+
+ SupplicantStaNetworkHal networkHandle =
+ checkSupplicantStaNetworkAndLogFailure(ifaceName, "roamToNetwork");
+ if (networkHandle == null || !networkHandle.setBssid(bssid)) {
loge("Failed to set new bssid on network: " + config.configKey());
return false;
}
- if (!reassociate()) {
+ if (!reassociate(ifaceName)) {
loge("Failed to trigger reassociate");
return false;
}
@@ -496,21 +615,22 @@
/**
* Load all the configured networks from wpa_supplicant.
*
+ * @param ifaceName Name of the interface.
* @param configs Map of configuration key to configuration objects corresponding to all
* the networks.
* @param networkExtras Map of extra configuration parameters stored in wpa_supplicant.conf
* @return true if succeeds, false otherwise.
*/
- public boolean loadNetworks(Map<String, WifiConfiguration> configs,
+ public boolean loadNetworks(@NonNull String ifaceName, Map<String, WifiConfiguration> configs,
SparseArray<Map<String, String>> networkExtras) {
synchronized (mLock) {
- List<Integer> networkIds = listNetworks();
+ List<Integer> networkIds = listNetworks(ifaceName);
if (networkIds == null) {
Log.e(TAG, "Failed to list networks");
return false;
}
for (Integer networkId : networkIds) {
- SupplicantStaNetworkHal network = getNetwork(networkId);
+ SupplicantStaNetworkHal network = getNetwork(ifaceName, networkId);
if (network == null) {
Log.e(TAG, "Failed to get network with ID: " + networkId);
return false;
@@ -539,7 +659,7 @@
if (duplicateConfig != null) {
// The network is already known. Overwrite the duplicate entry.
Log.i(TAG, "Replacing duplicate network: " + duplicateConfig.networkId);
- removeNetwork(duplicateConfig.networkId);
+ removeNetwork(ifaceName, duplicateConfig.networkId);
networkExtras.remove(duplicateConfig.networkId);
}
}
@@ -551,37 +671,40 @@
* Remove the request |networkId| from supplicant if it's the current network,
* if the current configured network matches |networkId|.
*
+ * @param ifaceName Name of the interface.
* @param networkId network id of the network to be removed from supplicant.
*/
- public void removeNetworkIfCurrent(int networkId) {
+ public void removeNetworkIfCurrent(@NonNull String ifaceName, int networkId) {
synchronized (mLock) {
- if (getCurrentNetworkId() == networkId) {
+ if (getCurrentNetworkId(ifaceName) == networkId) {
// Currently we only save 1 network in supplicant.
- removeAllNetworks();
+ removeAllNetworks(ifaceName);
}
}
}
/**
* Remove all networks from supplicant
+ *
+ * @param ifaceName Name of the interface.
*/
- public boolean removeAllNetworks() {
+ public boolean removeAllNetworks(@NonNull String ifaceName) {
synchronized (mLock) {
- ArrayList<Integer> networks = listNetworks();
+ ArrayList<Integer> networks = listNetworks(ifaceName);
if (networks == null) {
Log.e(TAG, "removeAllNetworks failed, got null networks");
return false;
}
for (int id : networks) {
- if (!removeNetwork(id)) {
+ if (!removeNetwork(ifaceName, id)) {
Log.e(TAG, "removeAllNetworks failed to remove network: " + id);
return false;
}
}
// Reset current network info. Probably not needed once we add support to remove/reset
// current network on receiving disconnection event from supplicant (b/32898136).
- mCurrentNetworkLocalConfig = null;
- mCurrentNetworkRemoteHandle = null;
+ mCurrentNetworkRemoteHandles.remove(ifaceName);
+ mCurrentNetworkLocalConfigs.remove(ifaceName);
return true;
}
}
@@ -589,113 +712,152 @@
/**
* Set the currently configured network's bssid.
*
+ * @param ifaceName Name of the interface.
* @param bssidStr Bssid to set in the form of "XX:XX:XX:XX:XX:XX"
* @return true if succeeds, false otherwise.
*/
- public boolean setCurrentNetworkBssid(String bssidStr) {
+ public boolean setCurrentNetworkBssid(@NonNull String ifaceName, String bssidStr) {
synchronized (mLock) {
- if (mCurrentNetworkRemoteHandle == null) return false;
- return mCurrentNetworkRemoteHandle.setBssid(bssidStr);
+ SupplicantStaNetworkHal networkHandle =
+ checkSupplicantStaNetworkAndLogFailure(ifaceName, "setCurrentNetworkBssid");
+ if (networkHandle == null) return false;
+ return networkHandle.setBssid(bssidStr);
}
}
/**
* Get the currently configured network's WPS NFC token.
*
+ * @param ifaceName Name of the interface.
* @return Hex string corresponding to the WPS NFC token.
*/
- public String getCurrentNetworkWpsNfcConfigurationToken() {
+ public String getCurrentNetworkWpsNfcConfigurationToken(@NonNull String ifaceName) {
synchronized (mLock) {
- if (mCurrentNetworkRemoteHandle == null) return null;
- return mCurrentNetworkRemoteHandle.getWpsNfcConfigurationToken();
+ SupplicantStaNetworkHal networkHandle =
+ checkSupplicantStaNetworkAndLogFailure(
+ ifaceName, "getCurrentNetworkWpsNfcConfigurationToken");
+ if (networkHandle == null) return null;
+ return networkHandle.getWpsNfcConfigurationToken();
}
}
/**
* Get the eap anonymous identity for the currently configured network.
*
+ * @param ifaceName Name of the interface.
* @return anonymous identity string if succeeds, null otherwise.
*/
- public String getCurrentNetworkEapAnonymousIdentity() {
+ public String getCurrentNetworkEapAnonymousIdentity(@NonNull String ifaceName) {
synchronized (mLock) {
- if (mCurrentNetworkRemoteHandle == null) return null;
- return mCurrentNetworkRemoteHandle.fetchEapAnonymousIdentity();
+ SupplicantStaNetworkHal networkHandle =
+ checkSupplicantStaNetworkAndLogFailure(
+ ifaceName, "getCurrentNetworkEapAnonymousIdentity");
+ if (networkHandle == null) return null;
+ return networkHandle.fetchEapAnonymousIdentity();
}
}
/**
* Send the eap identity response for the currently configured network.
*
+ * @param ifaceName Name of the interface.
* @param identityStr String to send.
* @return true if succeeds, false otherwise.
*/
- public boolean sendCurrentNetworkEapIdentityResponse(String identityStr) {
+ public boolean sendCurrentNetworkEapIdentityResponse(
+ @NonNull String ifaceName, String identityStr) {
synchronized (mLock) {
- if (mCurrentNetworkRemoteHandle == null) return false;
- return mCurrentNetworkRemoteHandle.sendNetworkEapIdentityResponse(identityStr);
+ SupplicantStaNetworkHal networkHandle =
+ checkSupplicantStaNetworkAndLogFailure(
+ ifaceName, "sendCurrentNetworkEapIdentityResponse");
+ if (networkHandle == null) return false;
+ return networkHandle.sendNetworkEapIdentityResponse(identityStr);
}
}
/**
* Send the eap sim gsm auth response for the currently configured network.
*
+ * @param ifaceName Name of the interface.
* @param paramsStr String to send.
* @return true if succeeds, false otherwise.
*/
- public boolean sendCurrentNetworkEapSimGsmAuthResponse(String paramsStr) {
+ public boolean sendCurrentNetworkEapSimGsmAuthResponse(
+ @NonNull String ifaceName, String paramsStr) {
synchronized (mLock) {
- if (mCurrentNetworkRemoteHandle == null) return false;
- return mCurrentNetworkRemoteHandle.sendNetworkEapSimGsmAuthResponse(paramsStr);
+ SupplicantStaNetworkHal networkHandle =
+ checkSupplicantStaNetworkAndLogFailure(
+ ifaceName, "sendCurrentNetworkEapSimGsmAuthResponse");
+ if (networkHandle == null) return false;
+ return networkHandle.sendNetworkEapSimGsmAuthResponse(paramsStr);
}
}
/**
* Send the eap sim gsm auth failure for the currently configured network.
*
+ * @param ifaceName Name of the interface.
* @return true if succeeds, false otherwise.
*/
- public boolean sendCurrentNetworkEapSimGsmAuthFailure() {
+ public boolean sendCurrentNetworkEapSimGsmAuthFailure(@NonNull String ifaceName) {
synchronized (mLock) {
- if (mCurrentNetworkRemoteHandle == null) return false;
- return mCurrentNetworkRemoteHandle.sendNetworkEapSimGsmAuthFailure();
+ SupplicantStaNetworkHal networkHandle =
+ checkSupplicantStaNetworkAndLogFailure(
+ ifaceName, "sendCurrentNetworkEapSimGsmAuthFailure");
+ if (networkHandle == null) return false;
+ return networkHandle.sendNetworkEapSimGsmAuthFailure();
}
}
/**
* Send the eap sim umts auth response for the currently configured network.
*
+ * @param ifaceName Name of the interface.
* @param paramsStr String to send.
* @return true if succeeds, false otherwise.
*/
- public boolean sendCurrentNetworkEapSimUmtsAuthResponse(String paramsStr) {
+ public boolean sendCurrentNetworkEapSimUmtsAuthResponse(
+ @NonNull String ifaceName, String paramsStr) {
synchronized (mLock) {
- if (mCurrentNetworkRemoteHandle == null) return false;
- return mCurrentNetworkRemoteHandle.sendNetworkEapSimUmtsAuthResponse(paramsStr);
+ SupplicantStaNetworkHal networkHandle =
+ checkSupplicantStaNetworkAndLogFailure(
+ ifaceName, "sendCurrentNetworkEapSimUmtsAuthResponse");
+ if (networkHandle == null) return false;
+ return networkHandle.sendNetworkEapSimUmtsAuthResponse(paramsStr);
}
}
/**
* Send the eap sim umts auts response for the currently configured network.
*
+ * @param ifaceName Name of the interface.
* @param paramsStr String to send.
* @return true if succeeds, false otherwise.
*/
- public boolean sendCurrentNetworkEapSimUmtsAutsResponse(String paramsStr) {
+ public boolean sendCurrentNetworkEapSimUmtsAutsResponse(
+ @NonNull String ifaceName, String paramsStr) {
synchronized (mLock) {
- if (mCurrentNetworkRemoteHandle == null) return false;
- return mCurrentNetworkRemoteHandle.sendNetworkEapSimUmtsAutsResponse(paramsStr);
+ SupplicantStaNetworkHal networkHandle =
+ checkSupplicantStaNetworkAndLogFailure(
+ ifaceName, "sendCurrentNetworkEapSimUmtsAutsResponse");
+ if (networkHandle == null) return false;
+ return networkHandle.sendNetworkEapSimUmtsAutsResponse(paramsStr);
}
}
/**
* Send the eap sim umts auth failure for the currently configured network.
*
+ * @param ifaceName Name of the interface.
* @return true if succeeds, false otherwise.
*/
- public boolean sendCurrentNetworkEapSimUmtsAuthFailure() {
+ public boolean sendCurrentNetworkEapSimUmtsAuthFailure(@NonNull String ifaceName) {
synchronized (mLock) {
- if (mCurrentNetworkRemoteHandle == null) return false;
- return mCurrentNetworkRemoteHandle.sendNetworkEapSimUmtsAuthFailure();
+ SupplicantStaNetworkHal networkHandle =
+ checkSupplicantStaNetworkAndLogFailure(
+ ifaceName, "sendCurrentNetworkEapSimUmtsAuthFailure");
+ if (networkHandle == null) return false;
+ return networkHandle.sendNetworkEapSimUmtsAuthFailure();
}
}
@@ -704,13 +866,14 @@
*
* @return The ISupplicantNetwork object for the new network, or null if the call fails
*/
- private SupplicantStaNetworkHal addNetwork() {
+ private SupplicantStaNetworkHal addNetwork(@NonNull String ifaceName) {
synchronized (mLock) {
final String methodStr = "addNetwork";
- if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return null;
+ ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
+ if (iface == null) return null;
Mutable<ISupplicantNetwork> newNetwork = new Mutable<>();
try {
- mISupplicantStaIface.addNetwork((SupplicantStatus status,
+ iface.addNetwork((SupplicantStatus status,
ISupplicantNetwork network) -> {
if (checkStatusAndLogFailure(status, methodStr)) {
newNetwork.value = network;
@@ -721,6 +884,7 @@
}
if (newNetwork.value != null) {
return getStaNetworkMockable(
+ ifaceName,
ISupplicantStaNetwork.asInterface(newNetwork.value.asBinder()));
} else {
return null;
@@ -733,12 +897,13 @@
*
* @return true if request is sent successfully, false otherwise.
*/
- private boolean removeNetwork(int id) {
+ private boolean removeNetwork(@NonNull String ifaceName, int id) {
synchronized (mLock) {
final String methodStr = "removeNetwork";
- if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
+ ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
+ if (iface == null) return false;
try {
- SupplicantStatus status = mISupplicantStaIface.removeNetwork(id);
+ SupplicantStatus status = iface.removeNetwork(id);
return checkStatusAndLogFailure(status, methodStr);
} catch (RemoteException e) {
handleRemoteException(e, methodStr);
@@ -750,15 +915,16 @@
/**
* Use this to mock the creation of SupplicantStaNetworkHal instance.
*
+ * @param ifaceName Name of the interface.
* @param iSupplicantStaNetwork ISupplicantStaNetwork instance retrieved from HIDL.
* @return The ISupplicantNetwork object for the given SupplicantNetworkId int, returns null if
* the call fails
*/
protected SupplicantStaNetworkHal getStaNetworkMockable(
- ISupplicantStaNetwork iSupplicantStaNetwork) {
+ @NonNull String ifaceName, ISupplicantStaNetwork iSupplicantStaNetwork) {
synchronized (mLock) {
SupplicantStaNetworkHal network =
- new SupplicantStaNetworkHal(iSupplicantStaNetwork, mIfaceName, mContext,
+ new SupplicantStaNetworkHal(iSupplicantStaNetwork, ifaceName, mContext,
mWifiMonitor);
if (network != null) {
network.enableVerboseLogging(mVerboseLoggingEnabled);
@@ -771,14 +937,14 @@
* @return The ISupplicantNetwork object for the given SupplicantNetworkId int, returns null if
* the call fails
*/
- private SupplicantStaNetworkHal getNetwork(int id) {
+ private SupplicantStaNetworkHal getNetwork(@NonNull String ifaceName, int id) {
synchronized (mLock) {
final String methodStr = "getNetwork";
+ ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
+ if (iface == null) return null;
Mutable<ISupplicantNetwork> gotNetwork = new Mutable<>();
- if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return null;
try {
- mISupplicantStaIface.getNetwork(id, (SupplicantStatus status,
- ISupplicantNetwork network) -> {
+ iface.getNetwork(id, (SupplicantStatus status, ISupplicantNetwork network) -> {
if (checkStatusAndLogFailure(status, methodStr)) {
gotNetwork.value = network;
}
@@ -788,6 +954,7 @@
}
if (gotNetwork.value != null) {
return getStaNetworkMockable(
+ ifaceName,
ISupplicantStaNetwork.asInterface(gotNetwork.value.asBinder()));
} else {
return null;
@@ -796,12 +963,13 @@
}
/** See ISupplicantStaNetwork.hal for documentation */
- private boolean registerCallback(ISupplicantStaIfaceCallback callback) {
+ private boolean registerCallback(
+ ISupplicantStaIface iface, ISupplicantStaIfaceCallback callback) {
synchronized (mLock) {
final String methodStr = "registerCallback";
- if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
+ if (iface == null) return false;
try {
- SupplicantStatus status = mISupplicantStaIface.registerCallback(callback);
+ SupplicantStatus status = iface.registerCallback(callback);
return checkStatusAndLogFailure(status, methodStr);
} catch (RemoteException e) {
handleRemoteException(e, methodStr);
@@ -814,14 +982,14 @@
* @return a list of SupplicantNetworkID ints for all networks controlled by supplicant, returns
* null if the call fails
*/
- private java.util.ArrayList<Integer> listNetworks() {
+ private java.util.ArrayList<Integer> listNetworks(@NonNull String ifaceName) {
synchronized (mLock) {
final String methodStr = "listNetworks";
+ ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
+ if (iface == null) return null;
Mutable<ArrayList<Integer>> networkIdList = new Mutable<>();
- if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return null;
try {
- mISupplicantStaIface.listNetworks((SupplicantStatus status,
- java.util.ArrayList<Integer> networkIds) -> {
+ iface.listNetworks((SupplicantStatus status, ArrayList<Integer> networkIds) -> {
if (checkStatusAndLogFailure(status, methodStr)) {
networkIdList.value = networkIds;
}
@@ -836,15 +1004,17 @@
/**
* Set WPS device name.
*
+ * @param ifaceName Name of the interface.
* @param name String to be set.
* @return true if request is sent successfully, false otherwise.
*/
- public boolean setWpsDeviceName(String name) {
+ public boolean setWpsDeviceName(@NonNull String ifaceName, String name) {
synchronized (mLock) {
final String methodStr = "setWpsDeviceName";
- if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
+ ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
+ if (iface == null) return false;
try {
- SupplicantStatus status = mISupplicantStaIface.setWpsDeviceName(name);
+ SupplicantStatus status = iface.setWpsDeviceName(name);
return checkStatusAndLogFailure(status, methodStr);
} catch (RemoteException e) {
handleRemoteException(e, methodStr);
@@ -856,10 +1026,11 @@
/**
* Set WPS device type.
*
+ * @param ifaceName Name of the interface.
* @param typeStr Type specified as a string. Used format: <categ>-<OUI>-<subcateg>
* @return true if request is sent successfully, false otherwise.
*/
- public boolean setWpsDeviceType(String typeStr) {
+ public boolean setWpsDeviceType(@NonNull String ifaceName, String typeStr) {
synchronized (mLock) {
try {
Matcher match = WPS_DEVICE_TYPE_PATTERN.matcher(typeStr);
@@ -876,7 +1047,7 @@
byteBuffer.putShort(categ);
byteBuffer.put(oui);
byteBuffer.putShort(subCateg);
- return setWpsDeviceType(bytes);
+ return setWpsDeviceType(ifaceName, bytes);
} catch (IllegalArgumentException e) {
Log.e(TAG, "Illegal argument " + typeStr, e);
return false;
@@ -884,12 +1055,13 @@
}
}
- private boolean setWpsDeviceType(byte[/* 8 */] type) {
+ private boolean setWpsDeviceType(@NonNull String ifaceName, byte[/* 8 */] type) {
synchronized (mLock) {
final String methodStr = "setWpsDeviceType";
- if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
+ ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
+ if (iface == null) return false;
try {
- SupplicantStatus status = mISupplicantStaIface.setWpsDeviceType(type);
+ SupplicantStatus status = iface.setWpsDeviceType(type);
return checkStatusAndLogFailure(status, methodStr);
} catch (RemoteException e) {
handleRemoteException(e, methodStr);
@@ -901,15 +1073,17 @@
/**
* Set WPS manufacturer.
*
+ * @param ifaceName Name of the interface.
* @param manufacturer String to be set.
* @return true if request is sent successfully, false otherwise.
*/
- public boolean setWpsManufacturer(String manufacturer) {
+ public boolean setWpsManufacturer(@NonNull String ifaceName, String manufacturer) {
synchronized (mLock) {
final String methodStr = "setWpsManufacturer";
- if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
+ ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
+ if (iface == null) return false;
try {
- SupplicantStatus status = mISupplicantStaIface.setWpsManufacturer(manufacturer);
+ SupplicantStatus status = iface.setWpsManufacturer(manufacturer);
return checkStatusAndLogFailure(status, methodStr);
} catch (RemoteException e) {
handleRemoteException(e, methodStr);
@@ -921,15 +1095,17 @@
/**
* Set WPS model name.
*
+ * @param ifaceName Name of the interface.
* @param modelName String to be set.
* @return true if request is sent successfully, false otherwise.
*/
- public boolean setWpsModelName(String modelName) {
+ public boolean setWpsModelName(@NonNull String ifaceName, String modelName) {
synchronized (mLock) {
final String methodStr = "setWpsModelName";
- if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
+ ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
+ if (iface == null) return false;
try {
- SupplicantStatus status = mISupplicantStaIface.setWpsModelName(modelName);
+ SupplicantStatus status = iface.setWpsModelName(modelName);
return checkStatusAndLogFailure(status, methodStr);
} catch (RemoteException e) {
handleRemoteException(e, methodStr);
@@ -941,15 +1117,17 @@
/**
* Set WPS model number.
*
+ * @param ifaceName Name of the interface.
* @param modelNumber String to be set.
* @return true if request is sent successfully, false otherwise.
*/
- public boolean setWpsModelNumber(String modelNumber) {
+ public boolean setWpsModelNumber(@NonNull String ifaceName, String modelNumber) {
synchronized (mLock) {
final String methodStr = "setWpsModelNumber";
- if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
+ ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
+ if (iface == null) return false;
try {
- SupplicantStatus status = mISupplicantStaIface.setWpsModelNumber(modelNumber);
+ SupplicantStatus status = iface.setWpsModelNumber(modelNumber);
return checkStatusAndLogFailure(status, methodStr);
} catch (RemoteException e) {
handleRemoteException(e, methodStr);
@@ -961,15 +1139,17 @@
/**
* Set WPS serial number.
*
+ * @param ifaceName Name of the interface.
* @param serialNumber String to be set.
* @return true if request is sent successfully, false otherwise.
*/
- public boolean setWpsSerialNumber(String serialNumber) {
+ public boolean setWpsSerialNumber(@NonNull String ifaceName, String serialNumber) {
synchronized (mLock) {
final String methodStr = "setWpsSerialNumber";
- if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
+ ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
+ if (iface == null) return false;
try {
- SupplicantStatus status = mISupplicantStaIface.setWpsSerialNumber(serialNumber);
+ SupplicantStatus status = iface.setWpsSerialNumber(serialNumber);
return checkStatusAndLogFailure(status, methodStr);
} catch (RemoteException e) {
handleRemoteException(e, methodStr);
@@ -981,26 +1161,28 @@
/**
* Set WPS config methods
*
+ * @param ifaceName Name of the interface.
* @param configMethodsStr List of config methods.
* @return true if request is sent successfully, false otherwise.
*/
- public boolean setWpsConfigMethods(String configMethodsStr) {
+ public boolean setWpsConfigMethods(@NonNull String ifaceName, String configMethodsStr) {
synchronized (mLock) {
short configMethodsMask = 0;
String[] configMethodsStrArr = configMethodsStr.split("\\s+");
for (int i = 0; i < configMethodsStrArr.length; i++) {
configMethodsMask |= stringToWpsConfigMethod(configMethodsStrArr[i]);
}
- return setWpsConfigMethods(configMethodsMask);
+ return setWpsConfigMethods(ifaceName, configMethodsMask);
}
}
- private boolean setWpsConfigMethods(short configMethods) {
+ private boolean setWpsConfigMethods(@NonNull String ifaceName, short configMethods) {
synchronized (mLock) {
final String methodStr = "setWpsConfigMethods";
- if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
+ ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
+ if (iface == null) return false;
try {
- SupplicantStatus status = mISupplicantStaIface.setWpsConfigMethods(configMethods);
+ SupplicantStatus status = iface.setWpsConfigMethods(configMethods);
return checkStatusAndLogFailure(status, methodStr);
} catch (RemoteException e) {
handleRemoteException(e, methodStr);
@@ -1012,14 +1194,16 @@
/**
* Trigger a reassociation even if the iface is currently connected.
*
+ * @param ifaceName Name of the interface.
* @return true if request is sent successfully, false otherwise.
*/
- public boolean reassociate() {
+ public boolean reassociate(@NonNull String ifaceName) {
synchronized (mLock) {
final String methodStr = "reassociate";
- if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
+ ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
+ if (iface == null) return false;
try {
- SupplicantStatus status = mISupplicantStaIface.reassociate();
+ SupplicantStatus status = iface.reassociate();
return checkStatusAndLogFailure(status, methodStr);
} catch (RemoteException e) {
handleRemoteException(e, methodStr);
@@ -1031,14 +1215,16 @@
/**
* Trigger a reconnection if the iface is disconnected.
*
+ * @param ifaceName Name of the interface.
* @return true if request is sent successfully, false otherwise.
*/
- public boolean reconnect() {
+ public boolean reconnect(@NonNull String ifaceName) {
synchronized (mLock) {
final String methodStr = "reconnect";
- if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
+ ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
+ if (iface == null) return false;
try {
- SupplicantStatus status = mISupplicantStaIface.reconnect();
+ SupplicantStatus status = iface.reconnect();
return checkStatusAndLogFailure(status, methodStr);
} catch (RemoteException e) {
handleRemoteException(e, methodStr);
@@ -1050,14 +1236,16 @@
/**
* Trigger a disconnection from the currently connected network.
*
+ * @param ifaceName Name of the interface.
* @return true if request is sent successfully, false otherwise.
*/
- public boolean disconnect() {
+ public boolean disconnect(@NonNull String ifaceName) {
synchronized (mLock) {
final String methodStr = "disconnect";
- if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
+ ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
+ if (iface == null) return false;
try {
- SupplicantStatus status = mISupplicantStaIface.disconnect();
+ SupplicantStatus status = iface.disconnect();
return checkStatusAndLogFailure(status, methodStr);
} catch (RemoteException e) {
handleRemoteException(e, methodStr);
@@ -1069,15 +1257,17 @@
/**
* Enable or disable power save mode.
*
+ * @param ifaceName Name of the interface.
* @param enable true to enable, false to disable.
* @return true if request is sent successfully, false otherwise.
*/
- public boolean setPowerSave(boolean enable) {
+ public boolean setPowerSave(@NonNull String ifaceName, boolean enable) {
synchronized (mLock) {
final String methodStr = "setPowerSave";
- if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
+ ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
+ if (iface == null) return false;
try {
- SupplicantStatus status = mISupplicantStaIface.setPowerSave(enable);
+ SupplicantStatus status = iface.setPowerSave(enable);
return checkStatusAndLogFailure(status, methodStr);
} catch (RemoteException e) {
handleRemoteException(e, methodStr);
@@ -1089,13 +1279,15 @@
/**
* Initiate TDLS discover with the specified AP.
*
+ * @param ifaceName Name of the interface.
* @param macAddress MAC Address of the AP.
* @return true if request is sent successfully, false otherwise.
*/
- public boolean initiateTdlsDiscover(String macAddress) {
+ public boolean initiateTdlsDiscover(@NonNull String ifaceName, String macAddress) {
synchronized (mLock) {
try {
- return initiateTdlsDiscover(NativeUtil.macAddressToByteArray(macAddress));
+ return initiateTdlsDiscover(
+ ifaceName, NativeUtil.macAddressToByteArray(macAddress));
} catch (IllegalArgumentException e) {
Log.e(TAG, "Illegal argument " + macAddress, e);
return false;
@@ -1103,12 +1295,13 @@
}
}
/** See ISupplicantStaIface.hal for documentation */
- private boolean initiateTdlsDiscover(byte[/* 6 */] macAddress) {
+ private boolean initiateTdlsDiscover(@NonNull String ifaceName, byte[/* 6 */] macAddress) {
synchronized (mLock) {
final String methodStr = "initiateTdlsDiscover";
- if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
+ ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
+ if (iface == null) return false;
try {
- SupplicantStatus status = mISupplicantStaIface.initiateTdlsDiscover(macAddress);
+ SupplicantStatus status = iface.initiateTdlsDiscover(macAddress);
return checkStatusAndLogFailure(status, methodStr);
} catch (RemoteException e) {
handleRemoteException(e, methodStr);
@@ -1120,13 +1313,14 @@
/**
* Initiate TDLS setup with the specified AP.
*
+ * @param ifaceName Name of the interface.
* @param macAddress MAC Address of the AP.
* @return true if request is sent successfully, false otherwise.
*/
- public boolean initiateTdlsSetup(String macAddress) {
+ public boolean initiateTdlsSetup(@NonNull String ifaceName, String macAddress) {
synchronized (mLock) {
try {
- return initiateTdlsSetup(NativeUtil.macAddressToByteArray(macAddress));
+ return initiateTdlsSetup(ifaceName, NativeUtil.macAddressToByteArray(macAddress));
} catch (IllegalArgumentException e) {
Log.e(TAG, "Illegal argument " + macAddress, e);
return false;
@@ -1134,12 +1328,13 @@
}
}
/** See ISupplicantStaIface.hal for documentation */
- private boolean initiateTdlsSetup(byte[/* 6 */] macAddress) {
+ private boolean initiateTdlsSetup(@NonNull String ifaceName, byte[/* 6 */] macAddress) {
synchronized (mLock) {
final String methodStr = "initiateTdlsSetup";
- if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
+ ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
+ if (iface == null) return false;
try {
- SupplicantStatus status = mISupplicantStaIface.initiateTdlsSetup(macAddress);
+ SupplicantStatus status = iface.initiateTdlsSetup(macAddress);
return checkStatusAndLogFailure(status, methodStr);
} catch (RemoteException e) {
handleRemoteException(e, methodStr);
@@ -1150,13 +1345,15 @@
/**
* Initiate TDLS teardown with the specified AP.
+ * @param ifaceName Name of the interface.
* @param macAddress MAC Address of the AP.
* @return true if request is sent successfully, false otherwise.
*/
- public boolean initiateTdlsTeardown(String macAddress) {
+ public boolean initiateTdlsTeardown(@NonNull String ifaceName, String macAddress) {
synchronized (mLock) {
try {
- return initiateTdlsTeardown(NativeUtil.macAddressToByteArray(macAddress));
+ return initiateTdlsTeardown(
+ ifaceName, NativeUtil.macAddressToByteArray(macAddress));
} catch (IllegalArgumentException e) {
Log.e(TAG, "Illegal argument " + macAddress, e);
return false;
@@ -1165,12 +1362,13 @@
}
/** See ISupplicantStaIface.hal for documentation */
- private boolean initiateTdlsTeardown(byte[/* 6 */] macAddress) {
+ private boolean initiateTdlsTeardown(@NonNull String ifaceName, byte[/* 6 */] macAddress) {
synchronized (mLock) {
final String methodStr = "initiateTdlsTeardown";
- if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
+ ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
+ if (iface == null) return false;
try {
- SupplicantStatus status = mISupplicantStaIface.initiateTdlsTeardown(macAddress);
+ SupplicantStatus status = iface.initiateTdlsTeardown(macAddress);
return checkStatusAndLogFailure(status, methodStr);
} catch (RemoteException e) {
handleRemoteException(e, methodStr);
@@ -1182,16 +1380,19 @@
/**
* Request the specified ANQP elements |elements| from the specified AP |bssid|.
*
+ * @param ifaceName Name of the interface.
* @param bssid BSSID of the AP
* @param infoElements ANQP elements to be queried. Refer to ISupplicantStaIface.AnqpInfoId.
* @param hs20SubTypes HS subtypes to be queried. Refer to ISupplicantStaIface.Hs20AnqpSubTypes.
* @return true if request is sent successfully, false otherwise.
*/
- public boolean initiateAnqpQuery(String bssid, ArrayList<Short> infoElements,
+ public boolean initiateAnqpQuery(@NonNull String ifaceName, String bssid,
+ ArrayList<Short> infoElements,
ArrayList<Integer> hs20SubTypes) {
synchronized (mLock) {
try {
return initiateAnqpQuery(
+ ifaceName,
NativeUtil.macAddressToByteArray(bssid), infoElements, hs20SubTypes);
} catch (IllegalArgumentException e) {
Log.e(TAG, "Illegal argument " + bssid, e);
@@ -1201,14 +1402,15 @@
}
/** See ISupplicantStaIface.hal for documentation */
- private boolean initiateAnqpQuery(byte[/* 6 */] macAddress,
+ private boolean initiateAnqpQuery(@NonNull String ifaceName, byte[/* 6 */] macAddress,
java.util.ArrayList<Short> infoElements, java.util.ArrayList<Integer> subTypes) {
synchronized (mLock) {
final String methodStr = "initiateAnqpQuery";
- if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
+ ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
+ if (iface == null) return false;
try {
- SupplicantStatus status = mISupplicantStaIface.initiateAnqpQuery(macAddress,
- infoElements, subTypes);
+ SupplicantStatus status = iface.initiateAnqpQuery(
+ macAddress, infoElements, subTypes);
return checkStatusAndLogFailure(status, methodStr);
} catch (RemoteException e) {
handleRemoteException(e, methodStr);
@@ -1220,14 +1422,16 @@
/**
* Request the specified ANQP ICON from the specified AP |bssid|.
*
+ * @param ifaceName Name of the interface.
* @param bssid BSSID of the AP
* @param fileName Name of the file to request.
* @return true if request is sent successfully, false otherwise.
*/
- public boolean initiateHs20IconQuery(String bssid, String fileName) {
+ public boolean initiateHs20IconQuery(@NonNull String ifaceName, String bssid, String fileName) {
synchronized (mLock) {
try {
- return initiateHs20IconQuery(NativeUtil.macAddressToByteArray(bssid), fileName);
+ return initiateHs20IconQuery(
+ ifaceName, NativeUtil.macAddressToByteArray(bssid), fileName);
} catch (IllegalArgumentException e) {
Log.e(TAG, "Illegal argument " + bssid, e);
return false;
@@ -1236,13 +1440,14 @@
}
/** See ISupplicantStaIface.hal for documentation */
- private boolean initiateHs20IconQuery(byte[/* 6 */] macAddress, String fileName) {
+ private boolean initiateHs20IconQuery(@NonNull String ifaceName,
+ byte[/* 6 */] macAddress, String fileName) {
synchronized (mLock) {
final String methodStr = "initiateHs20IconQuery";
- if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
+ ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
+ if (iface == null) return false;
try {
- SupplicantStatus status = mISupplicantStaIface.initiateHs20IconQuery(macAddress,
- fileName);
+ SupplicantStatus status = iface.initiateHs20IconQuery(macAddress, fileName);
return checkStatusAndLogFailure(status, methodStr);
} catch (RemoteException e) {
handleRemoteException(e, methodStr);
@@ -1254,15 +1459,17 @@
/**
* Makes a callback to HIDL to getMacAddress from supplicant
*
+ * @param ifaceName Name of the interface.
* @return string containing the MAC address, or null on a failed call
*/
- public String getMacAddress() {
+ public String getMacAddress(@NonNull String ifaceName) {
synchronized (mLock) {
final String methodStr = "getMacAddress";
- if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return null;
+ ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
+ if (iface == null) return null;
Mutable<String> gotMac = new Mutable<>();
try {
- mISupplicantStaIface.getMacAddress((SupplicantStatus status,
+ iface.getMacAddress((SupplicantStatus status,
byte[/* 6 */] macAddr) -> {
if (checkStatusAndLogFailure(status, methodStr)) {
gotMac.value = NativeUtil.macAddressFromByteArray(macAddr);
@@ -1278,14 +1485,16 @@
/**
* Start using the added RX filters.
*
+ * @param ifaceName Name of the interface.
* @return true if request is sent successfully, false otherwise.
*/
- public boolean startRxFilter() {
+ public boolean startRxFilter(@NonNull String ifaceName) {
synchronized (mLock) {
final String methodStr = "startRxFilter";
- if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
+ ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
+ if (iface == null) return false;
try {
- SupplicantStatus status = mISupplicantStaIface.startRxFilter();
+ SupplicantStatus status = iface.startRxFilter();
return checkStatusAndLogFailure(status, methodStr);
} catch (RemoteException e) {
handleRemoteException(e, methodStr);
@@ -1297,14 +1506,16 @@
/**
* Stop using the added RX filters.
*
+ * @param ifaceName Name of the interface.
* @return true if request is sent successfully, false otherwise.
*/
- public boolean stopRxFilter() {
+ public boolean stopRxFilter(@NonNull String ifaceName) {
synchronized (mLock) {
final String methodStr = "stopRxFilter";
- if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
+ ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
+ if (iface == null) return false;
try {
- SupplicantStatus status = mISupplicantStaIface.stopRxFilter();
+ SupplicantStatus status = iface.stopRxFilter();
return checkStatusAndLogFailure(status, methodStr);
} catch (RemoteException e) {
handleRemoteException(e, methodStr);
@@ -1316,11 +1527,12 @@
/**
* Add an RX filter.
*
+ * @param ifaceName Name of the interface.
* @param type one of {@link WifiNative#RX_FILTER_TYPE_V4_MULTICAST}
* {@link WifiNative#RX_FILTER_TYPE_V6_MULTICAST} values.
* @return true if request is sent successfully, false otherwise.
*/
- public boolean addRxFilter(int type) {
+ public boolean addRxFilter(@NonNull String ifaceName, int type) {
synchronized (mLock) {
byte halType;
switch (type) {
@@ -1334,16 +1546,17 @@
Log.e(TAG, "Invalid Rx Filter type: " + type);
return false;
}
- return addRxFilter(halType);
+ return addRxFilter(ifaceName, halType);
}
}
- public boolean addRxFilter(byte type) {
+ private boolean addRxFilter(@NonNull String ifaceName, byte type) {
synchronized (mLock) {
final String methodStr = "addRxFilter";
- if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
+ ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
+ if (iface == null) return false;
try {
- SupplicantStatus status = mISupplicantStaIface.addRxFilter(type);
+ SupplicantStatus status = iface.addRxFilter(type);
return checkStatusAndLogFailure(status, methodStr);
} catch (RemoteException e) {
handleRemoteException(e, methodStr);
@@ -1355,11 +1568,12 @@
/**
* Remove an RX filter.
*
+ * @param ifaceName Name of the interface.
* @param type one of {@link WifiNative#RX_FILTER_TYPE_V4_MULTICAST}
* {@link WifiNative#RX_FILTER_TYPE_V6_MULTICAST} values.
* @return true if request is sent successfully, false otherwise.
*/
- public boolean removeRxFilter(int type) {
+ public boolean removeRxFilter(@NonNull String ifaceName, int type) {
synchronized (mLock) {
byte halType;
switch (type) {
@@ -1373,16 +1587,17 @@
Log.e(TAG, "Invalid Rx Filter type: " + type);
return false;
}
- return removeRxFilter(halType);
+ return removeRxFilter(ifaceName, halType);
}
}
- public boolean removeRxFilter(byte type) {
+ private boolean removeRxFilter(@NonNull String ifaceName, byte type) {
synchronized (mLock) {
final String methodStr = "removeRxFilter";
- if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
+ ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
+ if (iface == null) return false;
try {
- SupplicantStatus status = mISupplicantStaIface.removeRxFilter(type);
+ SupplicantStatus status = iface.removeRxFilter(type);
return checkStatusAndLogFailure(status, methodStr);
} catch (RemoteException e) {
handleRemoteException(e, methodStr);
@@ -1394,12 +1609,13 @@
/**
* Set Bt co existense mode.
*
+ * @param ifaceName Name of the interface.
* @param mode one of the above {@link WifiNative#BLUETOOTH_COEXISTENCE_MODE_DISABLED},
* {@link WifiNative#BLUETOOTH_COEXISTENCE_MODE_ENABLED} or
* {@link WifiNative#BLUETOOTH_COEXISTENCE_MODE_SENSE}.
* @return true if request is sent successfully, false otherwise.
*/
- public boolean setBtCoexistenceMode(int mode) {
+ public boolean setBtCoexistenceMode(@NonNull String ifaceName, int mode) {
synchronized (mLock) {
byte halMode;
switch (mode) {
@@ -1416,16 +1632,17 @@
Log.e(TAG, "Invalid Bt Coex mode: " + mode);
return false;
}
- return setBtCoexistenceMode(halMode);
+ return setBtCoexistenceMode(ifaceName, halMode);
}
}
- private boolean setBtCoexistenceMode(byte mode) {
+ private boolean setBtCoexistenceMode(@NonNull String ifaceName, byte mode) {
synchronized (mLock) {
final String methodStr = "setBtCoexistenceMode";
- if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
+ ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
+ if (iface == null) return false;
try {
- SupplicantStatus status = mISupplicantStaIface.setBtCoexistenceMode(mode);
+ SupplicantStatus status = iface.setBtCoexistenceMode(mode);
return checkStatusAndLogFailure(status, methodStr);
} catch (RemoteException e) {
handleRemoteException(e, methodStr);
@@ -1436,16 +1653,18 @@
/** Enable or disable BT coexistence mode.
*
+ * @param ifaceName Name of the interface.
* @param enable true to enable, false to disable.
* @return true if request is sent successfully, false otherwise.
*/
- public boolean setBtCoexistenceScanModeEnabled(boolean enable) {
+ public boolean setBtCoexistenceScanModeEnabled(@NonNull String ifaceName, boolean enable) {
synchronized (mLock) {
final String methodStr = "setBtCoexistenceScanModeEnabled";
- if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
+ ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
+ if (iface == null) return false;
try {
SupplicantStatus status =
- mISupplicantStaIface.setBtCoexistenceScanModeEnabled(enable);
+ iface.setBtCoexistenceScanModeEnabled(enable);
return checkStatusAndLogFailure(status, methodStr);
} catch (RemoteException e) {
handleRemoteException(e, methodStr);
@@ -1457,15 +1676,17 @@
/**
* Enable or disable suspend mode optimizations.
*
+ * @param ifaceName Name of the interface.
* @param enable true to enable, false otherwise.
* @return true if request is sent successfully, false otherwise.
*/
- public boolean setSuspendModeEnabled(boolean enable) {
+ public boolean setSuspendModeEnabled(@NonNull String ifaceName, boolean enable) {
synchronized (mLock) {
final String methodStr = "setSuspendModeEnabled";
- if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
+ ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
+ if (iface == null) return false;
try {
- SupplicantStatus status = mISupplicantStaIface.setSuspendModeEnabled(enable);
+ SupplicantStatus status = iface.setSuspendModeEnabled(enable);
return checkStatusAndLogFailure(status, methodStr);
} catch (RemoteException e) {
handleRemoteException(e, methodStr);
@@ -1477,23 +1698,25 @@
/**
* Set country code.
*
+ * @param ifaceName Name of the interface.
* @param codeStr 2 byte ASCII string. For ex: US, CA.
* @return true if request is sent successfully, false otherwise.
*/
- public boolean setCountryCode(String codeStr) {
+ public boolean setCountryCode(@NonNull String ifaceName, String codeStr) {
synchronized (mLock) {
if (TextUtils.isEmpty(codeStr)) return false;
- return setCountryCode(NativeUtil.stringToByteArray(codeStr));
+ return setCountryCode(ifaceName, NativeUtil.stringToByteArray(codeStr));
}
}
/** See ISupplicantStaIface.hal for documentation */
- private boolean setCountryCode(byte[/* 2 */] code) {
+ private boolean setCountryCode(@NonNull String ifaceName, byte[/* 2 */] code) {
synchronized (mLock) {
final String methodStr = "setCountryCode";
- if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
+ ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
+ if (iface == null) return false;
try {
- SupplicantStatus status = mISupplicantStaIface.setCountryCode(code);
+ SupplicantStatus status = iface.setCountryCode(code);
return checkStatusAndLogFailure(status, methodStr);
} catch (RemoteException e) {
handleRemoteException(e, methodStr);
@@ -1505,15 +1728,17 @@
/**
* Start WPS pin registrar operation with the specified peer and pin.
*
+ * @param ifaceName Name of the interface.
* @param bssidStr BSSID of the peer.
* @param pin Pin to be used.
* @return true if request is sent successfully, false otherwise.
*/
- public boolean startWpsRegistrar(String bssidStr, String pin) {
+ public boolean startWpsRegistrar(@NonNull String ifaceName, String bssidStr, String pin) {
synchronized (mLock) {
if (TextUtils.isEmpty(bssidStr) || TextUtils.isEmpty(pin)) return false;
try {
- return startWpsRegistrar(NativeUtil.macAddressToByteArray(bssidStr), pin);
+ return startWpsRegistrar(
+ ifaceName, NativeUtil.macAddressToByteArray(bssidStr), pin);
} catch (IllegalArgumentException e) {
Log.e(TAG, "Illegal argument " + bssidStr, e);
return false;
@@ -1522,12 +1747,13 @@
}
/** See ISupplicantStaIface.hal for documentation */
- private boolean startWpsRegistrar(byte[/* 6 */] bssid, String pin) {
+ private boolean startWpsRegistrar(@NonNull String ifaceName, byte[/* 6 */] bssid, String pin) {
synchronized (mLock) {
final String methodStr = "startWpsRegistrar";
- if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
+ ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
+ if (iface == null) return false;
try {
- SupplicantStatus status = mISupplicantStaIface.startWpsRegistrar(bssid, pin);
+ SupplicantStatus status = iface.startWpsRegistrar(bssid, pin);
return checkStatusAndLogFailure(status, methodStr);
} catch (RemoteException e) {
handleRemoteException(e, methodStr);
@@ -1539,13 +1765,14 @@
/**
* Start WPS pin display operation with the specified peer.
*
+ * @param ifaceName Name of the interface.
* @param bssidStr BSSID of the peer. Use empty bssid to indicate wildcard.
* @return true if request is sent successfully, false otherwise.
*/
- public boolean startWpsPbc(String bssidStr) {
+ public boolean startWpsPbc(@NonNull String ifaceName, String bssidStr) {
synchronized (mLock) {
try {
- return startWpsPbc(NativeUtil.macAddressToByteArray(bssidStr));
+ return startWpsPbc(ifaceName, NativeUtil.macAddressToByteArray(bssidStr));
} catch (IllegalArgumentException e) {
Log.e(TAG, "Illegal argument " + bssidStr, e);
return false;
@@ -1554,12 +1781,13 @@
}
/** See ISupplicantStaIface.hal for documentation */
- private boolean startWpsPbc(byte[/* 6 */] bssid) {
+ private boolean startWpsPbc(@NonNull String ifaceName, byte[/* 6 */] bssid) {
synchronized (mLock) {
final String methodStr = "startWpsPbc";
- if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
+ ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
+ if (iface == null) return false;
try {
- SupplicantStatus status = mISupplicantStaIface.startWpsPbc(bssid);
+ SupplicantStatus status = iface.startWpsPbc(bssid);
return checkStatusAndLogFailure(status, methodStr);
} catch (RemoteException e) {
handleRemoteException(e, methodStr);
@@ -1571,16 +1799,18 @@
/**
* Start WPS pin keypad operation with the specified pin.
*
+ * @param ifaceName Name of the interface.
* @param pin Pin to be used.
* @return true if request is sent successfully, false otherwise.
*/
- public boolean startWpsPinKeypad(String pin) {
+ public boolean startWpsPinKeypad(@NonNull String ifaceName, String pin) {
if (TextUtils.isEmpty(pin)) return false;
synchronized (mLock) {
final String methodStr = "startWpsPinKeypad";
- if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
+ ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
+ if (iface == null) return false;
try {
- SupplicantStatus status = mISupplicantStaIface.startWpsPinKeypad(pin);
+ SupplicantStatus status = iface.startWpsPinKeypad(pin);
return checkStatusAndLogFailure(status, methodStr);
} catch (RemoteException e) {
handleRemoteException(e, methodStr);
@@ -1592,13 +1822,14 @@
/**
* Start WPS pin display operation with the specified peer.
*
+ * @param ifaceName Name of the interface.
* @param bssidStr BSSID of the peer. Use empty bssid to indicate wildcard.
* @return new pin generated on success, null otherwise.
*/
- public String startWpsPinDisplay(String bssidStr) {
+ public String startWpsPinDisplay(@NonNull String ifaceName, String bssidStr) {
synchronized (mLock) {
try {
- return startWpsPinDisplay(NativeUtil.macAddressToByteArray(bssidStr));
+ return startWpsPinDisplay(ifaceName, NativeUtil.macAddressToByteArray(bssidStr));
} catch (IllegalArgumentException e) {
Log.e(TAG, "Illegal argument " + bssidStr, e);
return null;
@@ -1607,13 +1838,14 @@
}
/** See ISupplicantStaIface.hal for documentation */
- private String startWpsPinDisplay(byte[/* 6 */] bssid) {
+ private String startWpsPinDisplay(@NonNull String ifaceName, byte[/* 6 */] bssid) {
synchronized (mLock) {
final String methodStr = "startWpsPinDisplay";
- if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return null;
+ ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
+ if (iface == null) return null;
final Mutable<String> gotPin = new Mutable<>();
try {
- mISupplicantStaIface.startWpsPinDisplay(bssid,
+ iface.startWpsPinDisplay(bssid,
(SupplicantStatus status, String pin) -> {
if (checkStatusAndLogFailure(status, methodStr)) {
gotPin.value = pin;
@@ -1629,14 +1861,16 @@
/**
* Cancels any ongoing WPS requests.
*
+ * @param ifaceName Name of the interface.
* @return true if request is sent successfully, false otherwise.
*/
- public boolean cancelWps() {
+ public boolean cancelWps(@NonNull String ifaceName) {
synchronized (mLock) {
final String methodStr = "cancelWps";
- if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
+ ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
+ if (iface == null) return false;
try {
- SupplicantStatus status = mISupplicantStaIface.cancelWps();
+ SupplicantStatus status = iface.cancelWps();
return checkStatusAndLogFailure(status, methodStr);
} catch (RemoteException e) {
handleRemoteException(e, methodStr);
@@ -1648,15 +1882,17 @@
/**
* Sets whether to use external sim for SIM/USIM processing.
*
+ * @param ifaceName Name of the interface.
* @param useExternalSim true to enable, false otherwise.
* @return true if request is sent successfully, false otherwise.
*/
- public boolean setExternalSim(boolean useExternalSim) {
+ public boolean setExternalSim(@NonNull String ifaceName, boolean useExternalSim) {
synchronized (mLock) {
final String methodStr = "setExternalSim";
- if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return false;
+ ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
+ if (iface == null) return false;
try {
- SupplicantStatus status = mISupplicantStaIface.setExternalSim(useExternalSim);
+ SupplicantStatus status = iface.setExternalSim(useExternalSim);
return checkStatusAndLogFailure(status, methodStr);
} catch (RemoteException e) {
handleRemoteException(e, methodStr);
@@ -1666,12 +1902,13 @@
}
/** See ISupplicant.hal for documentation */
- public boolean enableAutoReconnect(boolean enable) {
+ public boolean enableAutoReconnect(@NonNull String ifaceName, boolean enable) {
synchronized (mLock) {
final String methodStr = "enableAutoReconnect";
- if (!checkSupplicantAndLogFailure(methodStr)) return false;
+ ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
+ if (iface == null) return false;
try {
- SupplicantStatus status = mISupplicantStaIface.enableAutoReconnect(enable);
+ SupplicantStatus status = iface.enableAutoReconnect(enable);
return checkStatusAndLogFailure(status, methodStr);
} catch (RemoteException e) {
handleRemoteException(e, methodStr);
@@ -1759,13 +1996,30 @@
/**
* Returns false if SupplicantStaIface is null, and logs failure to call methodStr
*/
- private boolean checkSupplicantStaIfaceAndLogFailure(final String methodStr) {
+ private ISupplicantStaIface checkSupplicantStaIfaceAndLogFailure(
+ @NonNull String ifaceName, final String methodStr) {
synchronized (mLock) {
- if (mISupplicantStaIface == null) {
+ ISupplicantStaIface iface = getStaIface(ifaceName);
+ if (iface == null) {
Log.e(TAG, "Can't call " + methodStr + ", ISupplicantStaIface is null");
- return false;
+ return null;
}
- return true;
+ return iface;
+ }
+ }
+
+ /**
+ * Returns false if SupplicantStaNetwork is null, and logs failure to call methodStr
+ */
+ private SupplicantStaNetworkHal checkSupplicantStaNetworkAndLogFailure(
+ @NonNull String ifaceName, final String methodStr) {
+ synchronized (mLock) {
+ SupplicantStaNetworkHal networkHal = getCurrentNetworkRemoteHandle(ifaceName);
+ if (networkHal == null) {
+ Log.e(TAG, "Can't call " + methodStr + ", SupplicantStaNetwork is null");
+ return null;
+ }
+ return networkHal;
}
}
@@ -1922,9 +2176,13 @@
}
private class SupplicantStaIfaceHalCallback extends ISupplicantStaIfaceCallback.Stub {
- private static final int WLAN_REASON_IE_IN_4WAY_DIFFERS = 17; // IEEE 802.11i
+ private String mIfaceName;
private boolean mStateIsFourway = false; // Used to help check for PSK password mismatch
+ SupplicantStaIfaceHalCallback(@NonNull String ifaceName) {
+ mIfaceName = ifaceName;
+ }
+
/**
* Parses the provided payload into an ANQP element.
*
@@ -1993,10 +2251,11 @@
mStateIsFourway = (newState == ISupplicantStaIfaceCallback.State.FOURWAY_HANDSHAKE);
if (newSupplicantState == SupplicantState.COMPLETED) {
mWifiMonitor.broadcastNetworkConnectionEvent(
- mIfaceName, getCurrentNetworkId(), bssidStr);
+ mIfaceName, getCurrentNetworkId(mIfaceName), bssidStr);
}
mWifiMonitor.broadcastSupplicantStateChangeEvent(
- mIfaceName, getCurrentNetworkId(), wifiSsid, bssidStr, newSupplicantState);
+ mIfaceName, getCurrentNetworkId(mIfaceName), wifiSsid,
+ bssidStr, newSupplicantState);
}
}
@@ -2067,10 +2326,14 @@
+ " reasonCode=" + reasonCode);
}
if (mStateIsFourway
- && (!locallyGenerated || reasonCode != WLAN_REASON_IE_IN_4WAY_DIFFERS)) {
+ && (!locallyGenerated || reasonCode != ReasonCode.IE_IN_4WAY_DIFFERS)) {
mWifiMonitor.broadcastAuthenticationFailureEvent(
mIfaceName, WifiManager.ERROR_AUTH_FAILURE_WRONG_PSWD);
}
+ if (reasonCode == ReasonCode.IEEE_802_1X_AUTH_FAILED) {
+ mWifiMonitor.broadcastAuthenticationFailureEvent(
+ mIfaceName, WifiManager.ERROR_AUTH_FAILURE_EAP_FAILURE);
+ }
mWifiMonitor.broadcastNetworkDisconnectionEvent(
mIfaceName, locallyGenerated ? 1 : 0, reasonCode,
NativeUtil.macAddressFromByteArray(bssid));
diff --git a/service/java/com/android/server/wifi/VelocityBasedConnectedScore.java b/service/java/com/android/server/wifi/VelocityBasedConnectedScore.java
new file mode 100644
index 0000000..69643ce
--- /dev/null
+++ b/service/java/com/android/server/wifi/VelocityBasedConnectedScore.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wifi;
+
+import android.content.Context;
+import android.net.wifi.WifiInfo;
+
+import com.android.internal.R;
+import com.android.server.wifi.util.KalmanFilter;
+import com.android.server.wifi.util.Matrix;
+
+/**
+ * Class used to calculate scores for connected wifi networks and report it to the associated
+ * network agent.
+ */
+public class VelocityBasedConnectedScore extends ConnectedScore {
+
+ // Device configs. The values are examples.
+ private final int mThresholdMinimumRssi5; // -82
+ private final int mThresholdMinimumRssi24; // -85
+
+ private int mFrequency = 5000;
+ private double mThresholdMinimumRssi;
+ private double mThresholdAdjustment;
+ private final KalmanFilter mFilter;
+ private long mLastMillis;
+
+ public VelocityBasedConnectedScore(Context context, Clock clock) {
+ super(clock);
+ mThresholdMinimumRssi5 = context.getResources().getInteger(
+ R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz);
+ mThresholdMinimumRssi24 = context.getResources().getInteger(
+ R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz);
+ mThresholdMinimumRssi = mThresholdMinimumRssi5;
+ mFilter = new KalmanFilter();
+ mFilter.mH = new Matrix(2, new double[]{1.0, 0.0});
+ mFilter.mR = new Matrix(1, new double[]{1.0});
+ }
+
+ /**
+ * Set the Kalman filter's state transition matrix F and process noise covariance Q given
+ * a time step.
+ *
+ * @param dt delta time, in seconds
+ */
+ private void setDeltaTimeSeconds(double dt) {
+ mFilter.mF = new Matrix(2, new double[]{1.0, dt, 0.0, 1.0});
+ Matrix tG = new Matrix(1, new double[]{0.5 * dt * dt, dt});
+ double stda = 0.02; // standard deviation of modelled acceleration
+ mFilter.mQ = tG.dotTranspose(tG).dot(new Matrix(2, new double[]{
+ stda * stda, 0.0,
+ 0.0, stda * stda}));
+ }
+ /**
+ * Reset the filter state.
+ */
+ @Override
+ public void reset() {
+ mLastMillis = 0;
+ mThresholdAdjustment = 0.0;
+ }
+
+ /**
+ * Updates scoring state using RSSI and measurement noise estimate
+ * <p>
+ * This is useful if an RSSI comes from another source (e.g. scan results) and the
+ * expected noise varies by source.
+ *
+ * @param rssi signal strength (dB).
+ * @param millis millisecond-resolution time.
+ * @param standardDeviation of the RSSI.
+ */
+ @Override
+ public void updateUsingRssi(int rssi, long millis, double standardDeviation) {
+ if (millis <= 0) return;
+ if (mLastMillis <= 0 || millis < mLastMillis) {
+ double initialVariance = 9.0 * standardDeviation * standardDeviation;
+ mFilter.mx = new Matrix(1, new double[]{rssi, 0.0});
+ mFilter.mP = new Matrix(2, new double[]{initialVariance, 0.0, 0.0, 0.0});
+ mLastMillis = millis;
+ return;
+ }
+ double dt = (millis - mLastMillis) * 0.001;
+ mFilter.mR.put(0, 0, standardDeviation * standardDeviation);
+ setDeltaTimeSeconds(dt);
+ mFilter.predict();
+ mLastMillis = millis;
+ mFilter.update(new Matrix(1, new double[]{rssi}));
+ mFilteredRssi = mFilter.mx.get(0, 0);
+ mEstimatedRateOfRssiChange = mFilter.mx.get(1, 0);
+ }
+
+ /**
+ * Updates the state.
+ */
+ @Override
+ public void updateUsingWifiInfo(WifiInfo wifiInfo, long millis) {
+ int frequency = wifiInfo.getFrequency();
+ if (frequency != mFrequency) {
+ mLastMillis = 0; // Probably roamed; reset filter but retain threshold adjustment
+ // Consider resetting or partially resetting threshold adjustment
+ // Consider checking bssid
+ mFrequency = frequency;
+ mThresholdMinimumRssi =
+ mFrequency >= 5000 ? mThresholdMinimumRssi5 : mThresholdMinimumRssi24;
+ }
+ updateUsingRssi(wifiInfo.getRssi(), millis, mDefaultRssiStandardDeviation);
+ adjustThreshold(wifiInfo);
+ }
+
+ private double mFilteredRssi;
+ private double mEstimatedRateOfRssiChange;
+
+ /**
+ * Returns the most recently computed extimate of the RSSI.
+ */
+ public double getFilteredRssi() {
+ return mFilteredRssi;
+ }
+
+ /**
+ * Returns the estimated rate of change of RSSI, in dB/second
+ */
+ public double getEstimatedRateOfRssiChange() {
+ return mEstimatedRateOfRssiChange;
+ }
+
+ /**
+ * Returns the adjusted RSSI threshold
+ */
+ public double getAdjustedRssiThreshold() {
+ return mThresholdMinimumRssi + mThresholdAdjustment;
+ }
+
+ /**
+ * Adjusts the threshold if appropriate
+ * <p>
+ * If the (filtered) rssi is near or below the current effective threshold, and the
+ * rate of rssi change is small, and there is traffic, and the error rate is looking
+ * reasonable, then decrease the effective threshold to keep from dropping a perfectly good
+ * connection.
+ *
+ */
+ private void adjustThreshold(WifiInfo wifiInfo) {
+ if (mThresholdAdjustment < -7) return;
+ if (mFilteredRssi >= getAdjustedRssiThreshold() + 2.0) return;
+ if (Math.abs(mEstimatedRateOfRssiChange) >= 0.2) return;
+ if (wifiInfo.txSuccessRate < 10) return;
+ if (wifiInfo.rxSuccessRate < 10) return;
+ double probabilityOfSuccessfulTx = (
+ wifiInfo.txSuccessRate / (wifiInfo.txSuccessRate + wifiInfo.txBadRate)
+ );
+ if (probabilityOfSuccessfulTx >= 0.2) {
+ // May want this amount to vary with how close to threshold we are
+ mThresholdAdjustment -= 0.5;
+ }
+ }
+
+ /**
+ * Velocity scorer - predict the rssi a few seconds from now
+ */
+ @Override
+ public int generateScore() {
+ double badRssi = getAdjustedRssiThreshold();
+ double horizonSeconds = 15.0;
+ Matrix x = new Matrix(mFilter.mx);
+ double filteredRssi = x.get(0, 0);
+ setDeltaTimeSeconds(horizonSeconds);
+ x = mFilter.mF.dot(x);
+ double forecastRssi = x.get(0, 0);
+ if (forecastRssi > filteredRssi) {
+ forecastRssi = filteredRssi; // Be pessimistic about predicting an actual increase
+ }
+ int score = (int) (Math.round(forecastRssi) - badRssi) + WIFI_TRANSITION_SCORE;
+ return score;
+ }
+}
diff --git a/service/java/com/android/server/wifi/WakeupController.java b/service/java/com/android/server/wifi/WakeupController.java
new file mode 100644
index 0000000..a3c095a
--- /dev/null
+++ b/service/java/com/android/server/wifi/WakeupController.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wifi;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.os.Looper;
+import android.provider.Settings;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * WakeupController is responsible managing Auto Wifi.
+ *
+ * <p>It determines if and when to re-enable wifi after it has been turned off by the user.
+ */
+public class WakeupController {
+
+ // TODO(b/69624403) propagate this to Settings
+ private static final boolean USE_PLATFORM_WIFI_WAKE = false;
+
+ private final Context mContext;
+ private final Handler mHandler;
+ private final FrameworkFacade mFrameworkFacade;
+ private final ContentObserver mContentObserver;
+
+ /** Whether this feature is enabled in Settings. */
+ private boolean mWifiWakeupEnabled;
+
+ public WakeupController(
+ Context context,
+ Looper looper,
+ FrameworkFacade frameworkFacade) {
+ mContext = context;
+ mHandler = new Handler(looper);
+ mFrameworkFacade = frameworkFacade;
+ mContentObserver = new ContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange) {
+ mWifiWakeupEnabled = mFrameworkFacade.getIntegerSetting(
+ mContext, Settings.Global.WIFI_WAKEUP_ENABLED, 0) == 1;
+ }
+ };
+ mFrameworkFacade.registerContentObserver(mContext, Settings.Global.getUriFor(
+ Settings.Global.WIFI_WAKEUP_ENABLED), true, mContentObserver);
+ mContentObserver.onChange(false /* selfChange */);
+ }
+
+ /**
+ * Whether the feature is enabled in settings.
+ *
+ * <p>Note: This method is only used to determine whether or not to actually enable wifi. All
+ * other aspects of the WakeupController lifecycle operate normally irrespective of this.
+ */
+ @VisibleForTesting
+ boolean isEnabled() {
+ return mWifiWakeupEnabled;
+ }
+}
diff --git a/service/java/com/android/server/wifi/WifiBackupRestore.java b/service/java/com/android/server/wifi/WifiBackupRestore.java
index 60c3b48..ae5e411 100644
--- a/service/java/com/android/server/wifi/WifiBackupRestore.java
+++ b/service/java/com/android/server/wifi/WifiBackupRestore.java
@@ -228,9 +228,8 @@
}
return parseNetworkConfigurationsFromXml(in, rootTagDepth, version);
- } catch (XmlPullParserException e) {
- Log.e(TAG, "Error parsing the backup data: " + e);
- } catch (IOException e) {
+ } catch (XmlPullParserException | IOException | ClassCastException
+ | IllegalArgumentException e) {
Log.e(TAG, "Error parsing the backup data: " + e);
}
return null;
diff --git a/service/java/com/android/server/wifi/WifiConfigManager.java b/service/java/com/android/server/wifi/WifiConfigManager.java
index f256396..8fb61c2 100644
--- a/service/java/com/android/server/wifi/WifiConfigManager.java
+++ b/service/java/com/android/server/wifi/WifiConfigManager.java
@@ -200,12 +200,6 @@
@VisibleForTesting
public static final int LINK_CONFIGURATION_BSSID_MATCH_LENGTH = 16;
/**
- * Flags to be passed in for |canModifyNetwork| to decide if the change is minor and can
- * bypass the lockdown checks.
- */
- private static final boolean ALLOW_LOCKDOWN_CHECK_BYPASS = true;
- private static final boolean DISALLOW_LOCKDOWN_CHECK_BYPASS = false;
- /**
* Log tag for this class.
*/
private static final String TAG = "WifiConfigManager";
@@ -646,9 +640,8 @@
*
* @param config WifiConfiguration object corresponding to the network to be modified.
* @param uid UID of the app requesting the modification.
- * @param ignoreLockdown Ignore the configuration lockdown checks for connection attempts.
*/
- private boolean canModifyNetwork(WifiConfiguration config, int uid, boolean ignoreLockdown) {
+ private boolean canModifyNetwork(WifiConfiguration config, int uid) {
// System internals can always update networks; they're typically only
// making meteredHint or meteredOverride changes
if (uid == Process.SYSTEM_UID) {
@@ -685,12 +678,6 @@
final boolean isCreator = (config.creatorUid == uid);
- // Check if the |uid| holds the |NETWORK_SETTINGS| permission if the caller asks us to
- // bypass the lockdown checks.
- if (ignoreLockdown) {
- return mWifiPermissionsUtil.checkNetworkSettingsPermission(uid);
- }
-
// Check if device has DPM capability. If it has and |dpmi| is still null, then we
// treat this case with suspicion and bail out.
if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN)
@@ -980,7 +967,7 @@
return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
}
// Check for the app's permission before we let it update this network.
- if (!canModifyNetwork(existingInternalConfig, uid, DISALLOW_LOCKDOWN_CHECK_BYPASS)) {
+ if (!canModifyNetwork(existingInternalConfig, uid)) {
Log.e(TAG, "UID " + uid + " does not have permission to update configuration "
+ config.configKey());
return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
@@ -1107,9 +1094,10 @@
* Removes the specified network configuration from our database.
*
* @param config provided WifiConfiguration object.
+ * @param uid UID of the app requesting the network deletion.
* @return true if successful, false otherwise.
*/
- private boolean removeNetworkInternal(WifiConfiguration config) {
+ private boolean removeNetworkInternal(WifiConfiguration config, int uid) {
if (mVerboseLoggingEnabled) {
Log.v(TAG, "Removing network " + config.getPrintableSsid());
}
@@ -1127,7 +1115,9 @@
localLog("removeNetworkInternal: removed config."
+ " netId=" + config.networkId
- + " configKey=" + config.configKey());
+ + " configKey=" + config.configKey()
+ + " uid=" + Integer.toString(uid)
+ + " name=" + mContext.getPackageManager().getNameForUid(uid));
return true;
}
@@ -1147,12 +1137,12 @@
if (config == null) {
return false;
}
- if (!canModifyNetwork(config, uid, DISALLOW_LOCKDOWN_CHECK_BYPASS)) {
+ if (!canModifyNetwork(config, uid)) {
Log.e(TAG, "UID " + uid + " does not have permission to delete configuration "
+ config.configKey());
return false;
}
- if (!removeNetworkInternal(config)) {
+ if (!removeNetworkInternal(config, uid)) {
Log.e(TAG, "Failed to remove network " + config.getPrintableSsid());
return false;
}
@@ -1480,7 +1470,7 @@
if (config == null) {
return false;
}
- if (!canModifyNetwork(config, uid, DISALLOW_LOCKDOWN_CHECK_BYPASS)) {
+ if (!canModifyNetwork(config, uid)) {
Log.e(TAG, "UID " + uid + " does not have permission to update configuration "
+ config.configKey());
return false;
@@ -1515,7 +1505,7 @@
if (config == null) {
return false;
}
- if (!canModifyNetwork(config, uid, DISALLOW_LOCKDOWN_CHECK_BYPASS)) {
+ if (!canModifyNetwork(config, uid)) {
Log.e(TAG, "UID " + uid + " does not have permission to update configuration "
+ config.configKey());
return false;
@@ -1532,18 +1522,13 @@
}
/**
- * Checks if the |uid| has the necessary permission to force a connection to a network
- * and updates the last connected UID for the provided configuration.
+ * Updates the last connected UID for the provided configuration.
*
* @param networkId network ID corresponding to the network.
* @param uid uid of the app requesting the connection.
- * @return true if |uid| has the necessary permission to trigger explicit connection to the
- * network, false otherwise.
- * Note: This returns true only for the system settings/sysui app which holds the
- * {@link android.Manifest.permission#NETWORK_SETTINGS} permission. We don't want to let
- * any other app force connection to a network.
+ * @return true if the network was found, false otherwise.
*/
- public boolean checkAndUpdateLastConnectUid(int networkId, int uid) {
+ public boolean updateLastConnectUid(int networkId, int uid) {
if (mVerboseLoggingEnabled) {
Log.v(TAG, "Update network last connect UID for " + networkId);
}
@@ -1555,11 +1540,6 @@
if (config == null) {
return false;
}
- if (!canModifyNetwork(config, uid, ALLOW_LOCKDOWN_CHECK_BYPASS)) {
- Log.e(TAG, "UID " + uid + " does not have permission to update configuration "
- + config.configKey());
- return false;
- }
config.lastConnectUid = uid;
return true;
}
diff --git a/service/java/com/android/server/wifi/WifiConfigurationUtil.java b/service/java/com/android/server/wifi/WifiConfigurationUtil.java
index dadc8a4..ea58549 100644
--- a/service/java/com/android/server/wifi/WifiConfigurationUtil.java
+++ b/service/java/com/android/server/wifi/WifiConfigurationUtil.java
@@ -437,9 +437,10 @@
/**
* Check if the provided two networks are the same.
+ * Note: This does not check if network selection BSSID's are the same.
*
- * @param config Configuration corresponding to a network.
- * @param config1 Configuration corresponding to another network.
+ * @param config Configuration corresponding to a network.
+ * @param config1 Configuration corresponding to another network.
*
* @return true if |config| and |config1| are the same network.
* false otherwise.
@@ -457,13 +458,6 @@
if (!Objects.equals(config.SSID, config1.SSID)) {
return false;
}
- String networkSelectionBSSID = config.getNetworkSelectionStatus()
- .getNetworkSelectionBSSID();
- String networkSelectionBSSID1 = config1.getNetworkSelectionStatus()
- .getNetworkSelectionBSSID();
- if (!Objects.equals(networkSelectionBSSID, networkSelectionBSSID1)) {
- return false;
- }
if (WifiConfigurationUtil.hasCredentialChanged(config, config1)) {
return false;
}
diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java
index 4b8e682..f14a57f 100644
--- a/service/java/com/android/server/wifi/WifiInjector.java
+++ b/service/java/com/android/server/wifi/WifiInjector.java
@@ -16,6 +16,7 @@
package com.android.server.wifi;
+import android.annotation.NonNull;
import android.app.ActivityManager;
import android.content.Context;
import android.net.NetworkKey;
@@ -23,7 +24,6 @@
import android.net.wifi.IApInterface;
import android.net.wifi.IWifiScanner;
import android.net.wifi.IWificond;
-import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiNetworkScoreCache;
import android.net.wifi.WifiScanner;
@@ -116,11 +116,13 @@
private final PasspointManager mPasspointManager;
private final SIMAccessor mSimAccessor;
private HandlerThread mWifiAwareHandlerThread;
+ private HandlerThread mRttHandlerThread;
private HalDeviceManager mHalDeviceManager;
private final IBatteryStats mBatteryStats;
private final WifiStateTracker mWifiStateTracker;
private final Runtime mJavaRuntime;
private final SelfRecovery mSelfRecovery;
+ private final WakeupController mWakeupController;
private final boolean mUseRealLogger;
@@ -162,7 +164,7 @@
mWifiMetrics = new WifiMetrics(mClock, wifiStateMachineLooper, awareMetrics);
// Modules interacting with Native.
mWifiMonitor = new WifiMonitor(this);
- mHalDeviceManager = new HalDeviceManager();
+ mHalDeviceManager = new HalDeviceManager(mClock);
mWifiVendorHal =
new WifiVendorHal(mHalDeviceManager, mWifiStateMachineHandlerThread.getLooper());
mSupplicantStaIfaceHal = new SupplicantStaIfaceHal(mContext, mWifiMonitor);
@@ -229,6 +231,8 @@
mWifiConfigManager, mWifiConfigStore, mWifiStateMachine,
new OpenNetworkRecommender(),
new ConnectToNetworkNotificationBuilder(mContext, mFrameworkFacade));
+ mWakeupController = new WakeupController(mContext,
+ mWifiStateMachineHandlerThread.getLooper(), mFrameworkFacade);
mLockManager = new WifiLockManager(mContext, BatteryStatsService.getService());
mWifiController = new WifiController(mContext, mWifiStateMachine, mSettingsStore,
mLockManager, mWifiServiceHandlerThread.getLooper(), mFrameworkFacade);
@@ -348,6 +352,10 @@
return mPasspointManager;
}
+ public WakeupController getWakeupController() {
+ return mWakeupController;
+ }
+
public TelephonyManager makeTelephonyManager() {
// may not be available when WiFi starts
return (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
@@ -369,16 +377,18 @@
* changes
* @param listener listener for SoftApManager
* @param apInterface network interface to start hostapd against
- * @param config softAp WifiConfiguration
+ * @param ifaceName name of the ap interface
+ * @param config SoftApModeConfiguration object holding the config and mode
* @return an instance of SoftApManager
*/
public SoftApManager makeSoftApManager(INetworkManagementService nmService,
SoftApManager.Listener listener,
- IApInterface apInterface,
- WifiConfiguration config) {
- return new SoftApManager(mWifiServiceHandlerThread.getLooper(),
+ @NonNull IApInterface apInterface,
+ @NonNull String ifaceName,
+ @NonNull SoftApModeConfiguration config) {
+ return new SoftApManager(mContext, mWifiServiceHandlerThread.getLooper(),
mWifiNative, mCountryCode.getCountryCode(),
- listener, apInterface, nmService,
+ listener, apInterface, ifaceName, nmService,
mWifiApConfigStore, config, mWifiMetrics);
}
@@ -455,6 +465,19 @@
}
/**
+ * Returns a singleton instance of a HandlerThread for injection. Uses lazy initialization.
+ *
+ * TODO: share worker thread with other Wi-Fi handlers (b/27924886)
+ */
+ public HandlerThread getRttHandlerThread() {
+ if (mRttHandlerThread == null) { // lazy initialization
+ mRttHandlerThread = new HandlerThread("wifiRttService");
+ mRttHandlerThread.start();
+ }
+ return mRttHandlerThread;
+ }
+
+ /**
* Returns a single instance of HalDeviceManager for injection.
*/
public HalDeviceManager getHalDeviceManager() {
diff --git a/service/java/com/android/server/wifi/WifiMetrics.java b/service/java/com/android/server/wifi/WifiMetrics.java
index 071b4f8..4e277a1 100644
--- a/service/java/com/android/server/wifi/WifiMetrics.java
+++ b/service/java/com/android/server/wifi/WifiMetrics.java
@@ -31,16 +31,21 @@
import android.util.Pair;
import android.util.SparseIntArray;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.server.wifi.aware.WifiAwareMetrics;
+import com.android.server.wifi.hotspot2.ANQPNetworkKey;
import com.android.server.wifi.hotspot2.NetworkDetail;
import com.android.server.wifi.hotspot2.PasspointManager;
import com.android.server.wifi.hotspot2.PasspointMatch;
import com.android.server.wifi.hotspot2.PasspointProvider;
+import com.android.server.wifi.hotspot2.Utils;
import com.android.server.wifi.nano.WifiMetricsProto;
import com.android.server.wifi.nano.WifiMetricsProto.ConnectToNetworkNotificationAndActionCount;
import com.android.server.wifi.nano.WifiMetricsProto.PnoScanMetrics;
+import com.android.server.wifi.nano.WifiMetricsProto.SoftApConnectedClientsEvent;
import com.android.server.wifi.nano.WifiMetricsProto.StaEvent;
import com.android.server.wifi.nano.WifiMetricsProto.StaEvent.ConfigInfo;
+import com.android.server.wifi.nano.WifiMetricsProto.WpsMetrics;
import com.android.server.wifi.util.InformationElementUtil;
import com.android.server.wifi.util.ScanResultUtil;
@@ -49,9 +54,11 @@
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Calendar;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
import java.util.Set;
/**
@@ -76,6 +83,8 @@
public static final long TIMEOUT_RSSI_DELTA_MILLIS = 3000;
private static final int MIN_WIFI_SCORE = 0;
private static final int MAX_WIFI_SCORE = NetworkAgent.WIFI_BASE_SCORE;
+ @VisibleForTesting
+ static final int LOW_WIFI_SCORE = 50; // Mobile data score
private final Object mLock = new Object();
private static final int MAX_CONNECTION_EVENTS = 256;
// Largest bucket in the NumConnectableNetworkCount histogram,
@@ -84,12 +93,18 @@
public static final int MAX_CONNECTABLE_BSSID_NETWORK_BUCKET = 50;
public static final int MAX_TOTAL_SCAN_RESULT_SSIDS_BUCKET = 100;
public static final int MAX_TOTAL_SCAN_RESULTS_BUCKET = 250;
+ public static final int MAX_TOTAL_PASSPOINT_APS_BUCKET = 50;
+ public static final int MAX_TOTAL_PASSPOINT_UNIQUE_ESS_BUCKET = 20;
+ public static final int MAX_PASSPOINT_APS_PER_UNIQUE_ESS_BUCKET = 50;
private static final int CONNECT_TO_NETWORK_NOTIFICATION_ACTION_KEY_MULTIPLIER = 1000;
+ // Max limit for number of soft AP related events, extra events will be dropped.
+ private static final int MAX_NUM_SOFT_AP_EVENTS = 256;
private Clock mClock;
private boolean mScreenOn;
private int mWifiState;
private WifiAwareMetrics mWifiAwareMetrics;
private final PnoScanMetrics mPnoScanMetrics = new PnoScanMetrics();
+ private final WpsMetrics mWpsMetrics = new WpsMetrics();
private Handler mHandler;
private WifiConfigManager mWifiConfigManager;
private WifiNetworkSelector mWifiNetworkSelector;
@@ -160,6 +175,17 @@
private boolean mIsWifiNetworksAvailableNotificationOn = false;
private int mNumOpenNetworkConnectMessageFailedToSend = 0;
private int mNumOpenNetworkRecommendationUpdates = 0;
+ /** List of soft AP events related to number of connected clients in tethered mode */
+ private final List<SoftApConnectedClientsEvent> mSoftApEventListTethered = new ArrayList<>();
+ /** List of soft AP events related to number of connected clients in local only mode */
+ private final List<SoftApConnectedClientsEvent> mSoftApEventListLocalOnly = new ArrayList<>();
+
+ private final SparseIntArray mObservedHotspotR1ApInScanHistogram = new SparseIntArray();
+ private final SparseIntArray mObservedHotspotR2ApInScanHistogram = new SparseIntArray();
+ private final SparseIntArray mObservedHotspotR1EssInScanHistogram = new SparseIntArray();
+ private final SparseIntArray mObservedHotspotR2EssInScanHistogram = new SparseIntArray();
+ private final SparseIntArray mObservedHotspotR1ApsPerEssInScanHistogram = new SparseIntArray();
+ private final SparseIntArray mObservedHotspotR2ApsPerEssInScanHistogram = new SparseIntArray();
class RouterFingerPrint {
private WifiMetricsProto.RouterFingerPrint mRouterFingerPrintProto;
@@ -465,6 +491,78 @@
}
}
+ /**
+ * Increment total number of wps connection attempts
+ */
+ public void incrementWpsAttemptCount() {
+ synchronized (mLock) {
+ mWpsMetrics.numWpsAttempts++;
+ }
+ }
+
+ /**
+ * Increment total number of wps connection success
+ */
+ public void incrementWpsSuccessCount() {
+ synchronized (mLock) {
+ mWpsMetrics.numWpsSuccess++;
+ }
+ }
+
+ /**
+ * Increment total number of wps failure on start
+ */
+ public void incrementWpsStartFailureCount() {
+ synchronized (mLock) {
+ mWpsMetrics.numWpsStartFailure++;
+ }
+ }
+
+ /**
+ * Increment total number of wps overlap failure
+ */
+ public void incrementWpsOverlapFailureCount() {
+ synchronized (mLock) {
+ mWpsMetrics.numWpsOverlapFailure++;
+ }
+ }
+
+ /**
+ * Increment total number of wps timeout failure
+ */
+ public void incrementWpsTimeoutFailureCount() {
+ synchronized (mLock) {
+ mWpsMetrics.numWpsTimeoutFailure++;
+ }
+ }
+
+ /**
+ * Increment total number of other wps failure during connection
+ */
+ public void incrementWpsOtherConnectionFailureCount() {
+ synchronized (mLock) {
+ mWpsMetrics.numWpsOtherConnectionFailure++;
+ }
+ }
+
+ /**
+ * Increment total number of supplicant failure after wps
+ */
+ public void incrementWpsSupplicantFailureCount() {
+ synchronized (mLock) {
+ mWpsMetrics.numWpsSupplicantFailure++;
+ }
+ }
+
+ /**
+ * Increment total number of wps cancellation
+ */
+ public void incrementWpsCancellationCount() {
+ synchronized (mLock) {
+ mWpsMetrics.numWpsCancellation++;
+ }
+ }
+
// Values used for indexing SystemStateEntries
private static final int SCREEN_ON = 1;
private static final int SCREEN_OFF = 0;
@@ -1041,10 +1139,14 @@
}
}
+ private boolean mWifiWins = false; // Based on scores, use wifi instead of mobile data?
+
/**
* Increments occurence of a particular wifi score calculated
* in WifiScoreReport by current connected network. Scores are bounded
- * within [MIN_WIFI_SCORE, MAX_WIFI_SCORE] to limit size of SparseArray
+ * within [MIN_WIFI_SCORE, MAX_WIFI_SCORE] to limit size of SparseArray.
+ *
+ * Also records events when the current score breaches significant thresholds.
*/
public void incrementWifiScoreCount(int score) {
if (score < MIN_WIFI_SCORE || score > MAX_WIFI_SCORE) {
@@ -1053,6 +1155,20 @@
synchronized (mLock) {
int count = mWifiScoreCounts.get(score);
mWifiScoreCounts.put(score, count + 1);
+
+ boolean wifiWins = mWifiWins;
+ if (mWifiWins && score < LOW_WIFI_SCORE) {
+ wifiWins = false;
+ } else if (!mWifiWins && score > LOW_WIFI_SCORE) {
+ wifiWins = true;
+ }
+ mLastScore = score;
+ if (wifiWins != mWifiWins) {
+ mWifiWins = wifiWins;
+ StaEvent event = new StaEvent();
+ event.type = StaEvent.TYPE_SCORE_BREACH;
+ addStaEvent(event);
+ }
}
}
@@ -1092,6 +1208,53 @@
}
/**
+ * Adds a record indicating the current up state of soft AP
+ */
+ public void addSoftApUpChangedEvent(boolean isUp, int mode) {
+ SoftApConnectedClientsEvent event = new SoftApConnectedClientsEvent();
+ event.eventType = isUp ? SoftApConnectedClientsEvent.SOFT_AP_UP :
+ SoftApConnectedClientsEvent.SOFT_AP_DOWN;
+ event.numConnectedClients = 0;
+ addSoftApConnectedClientsEvent(event, mode);
+ }
+
+ /**
+ * Adds a record for current number of associated stations to soft AP
+ */
+ public void addSoftApNumAssociatedStationsChangedEvent(int numStations, int mode) {
+ SoftApConnectedClientsEvent event = new SoftApConnectedClientsEvent();
+ event.eventType = SoftApConnectedClientsEvent.NUM_CLIENTS_CHANGED;
+ event.numConnectedClients = numStations;
+ addSoftApConnectedClientsEvent(event, mode);
+ }
+
+ /**
+ * Adds a record to the corresponding event list based on mode param
+ */
+ private void addSoftApConnectedClientsEvent(SoftApConnectedClientsEvent event, int mode) {
+ synchronized (mLock) {
+ List<SoftApConnectedClientsEvent> softApEventList;
+ switch (mode) {
+ case WifiManager.IFACE_IP_MODE_TETHERED:
+ softApEventList = mSoftApEventListTethered;
+ break;
+ case WifiManager.IFACE_IP_MODE_LOCAL_ONLY:
+ softApEventList = mSoftApEventListLocalOnly;
+ break;
+ default:
+ return;
+ }
+
+ if (softApEventList.size() > MAX_NUM_SOFT_AP_EVENTS) {
+ return;
+ }
+
+ event.timeStampMillis = mClock.getWallClockMillis();
+ softApEventList.add(event);
+ }
+ }
+
+ /**
* Increment number of times the HAL crashed.
*/
public void incrementNumHalCrashes() {
@@ -1192,6 +1355,10 @@
Set<PasspointProvider> savedPasspointProviderProfiles =
new HashSet<PasspointProvider>();
int savedPasspointProviderBssids = 0;
+ int passpointR1Aps = 0;
+ int passpointR2Aps = 0;
+ Map<ANQPNetworkKey, Integer> passpointR1UniqueEss = new HashMap<>();
+ Map<ANQPNetworkKey, Integer> passpointR2UniqueEss = new HashMap<>();
for (ScanDetail scanDetail : scanDetails) {
NetworkDetail networkDetail = scanDetail.getNetworkDetail();
ScanResult scanResult = scanDetail.getScanResult();
@@ -1205,6 +1372,36 @@
providerMatch =
mPasspointManager.matchProvider(scanResult);
passpointProvider = providerMatch != null ? providerMatch.first : null;
+
+ if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R1) {
+ passpointR1Aps++;
+ } else if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R2) {
+ passpointR2Aps++;
+ }
+
+ long bssid = 0;
+ boolean validBssid = false;
+ try {
+ bssid = Utils.parseMac(scanResult.BSSID);
+ validBssid = true;
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG,
+ "Invalid BSSID provided in the scan result: " + scanResult.BSSID);
+ }
+ if (validBssid) {
+ ANQPNetworkKey uniqueEss = ANQPNetworkKey.buildKey(scanResult.SSID, bssid,
+ scanResult.hessid, networkDetail.getAnqpDomainID());
+ if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R1) {
+ Integer countObj = passpointR1UniqueEss.get(uniqueEss);
+ int count = countObj == null ? 0 : countObj;
+ passpointR1UniqueEss.put(uniqueEss, count + 1);
+ } else if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R2) {
+ Integer countObj = passpointR2UniqueEss.get(uniqueEss);
+ int count = countObj == null ? 0 : countObj;
+ passpointR2UniqueEss.put(uniqueEss, count + 1);
+ }
+ }
+
}
ssids.add(matchInfo);
bssids++;
@@ -1245,6 +1442,18 @@
savedPasspointProviderProfiles.size());
incrementBssid(mAvailableSavedPasspointProviderBssidsInScanHistogram,
savedPasspointProviderBssids);
+ incrementTotalPasspointAps(mObservedHotspotR1ApInScanHistogram, passpointR1Aps);
+ incrementTotalPasspointAps(mObservedHotspotR2ApInScanHistogram, passpointR2Aps);
+ incrementTotalUniquePasspointEss(mObservedHotspotR1EssInScanHistogram,
+ passpointR1UniqueEss.size());
+ incrementTotalUniquePasspointEss(mObservedHotspotR2EssInScanHistogram,
+ passpointR2UniqueEss.size());
+ for (Integer count : passpointR1UniqueEss.values()) {
+ incrementPasspointPerUniqueEss(mObservedHotspotR1ApsPerEssInScanHistogram, count);
+ }
+ for (Integer count : passpointR2UniqueEss.values()) {
+ incrementPasspointPerUniqueEss(mObservedHotspotR2ApsPerEssInScanHistogram, count);
+ }
}
}
@@ -1561,6 +1770,53 @@
+ mNumOpenNetworkRecommendationUpdates);
pw.println("mWifiLogProto.numOpenNetworkConnectMessageFailedToSend="
+ mNumOpenNetworkConnectMessageFailedToSend);
+
+ pw.println("mWifiLogProto.observedHotspotR1ApInScanHistogram="
+ + mObservedHotspotR1ApInScanHistogram);
+ pw.println("mWifiLogProto.observedHotspotR2ApInScanHistogram="
+ + mObservedHotspotR2ApInScanHistogram);
+ pw.println("mWifiLogProto.observedHotspotR1EssInScanHistogram="
+ + mObservedHotspotR1EssInScanHistogram);
+ pw.println("mWifiLogProto.observedHotspotR2EssInScanHistogram="
+ + mObservedHotspotR2EssInScanHistogram);
+ pw.println("mWifiLogProto.observedHotspotR1ApsPerEssInScanHistogram="
+ + mObservedHotspotR1ApsPerEssInScanHistogram);
+ pw.println("mWifiLogProto.observedHotspotR2ApsPerEssInScanHistogram="
+ + mObservedHotspotR2ApsPerEssInScanHistogram);
+
+ pw.println("mSoftApTetheredEvents:");
+ for (SoftApConnectedClientsEvent event : mSoftApEventListTethered) {
+ StringBuilder eventLine = new StringBuilder();
+ eventLine.append("event_type=" + event.eventType);
+ eventLine.append(",time_stamp_millis=" + event.timeStampMillis);
+ eventLine.append(",num_connected_clients=" + event.numConnectedClients);
+ pw.println(eventLine.toString());
+ }
+ pw.println("mSoftApLocalOnlyEvents:");
+ for (SoftApConnectedClientsEvent event : mSoftApEventListLocalOnly) {
+ StringBuilder eventLine = new StringBuilder();
+ eventLine.append("event_type=" + event.eventType);
+ eventLine.append(",time_stamp_millis=" + event.timeStampMillis);
+ eventLine.append(",num_connected_clients=" + event.numConnectedClients);
+ pw.println(eventLine.toString());
+ }
+
+ pw.println("mWpsMetrics.numWpsAttempts="
+ + mWpsMetrics.numWpsAttempts);
+ pw.println("mWpsMetrics.numWpsSuccess="
+ + mWpsMetrics.numWpsSuccess);
+ pw.println("mWpsMetrics.numWpsStartFailure="
+ + mWpsMetrics.numWpsStartFailure);
+ pw.println("mWpsMetrics.numWpsOverlapFailure="
+ + mWpsMetrics.numWpsOverlapFailure);
+ pw.println("mWpsMetrics.numWpsTimeoutFailure="
+ + mWpsMetrics.numWpsTimeoutFailure);
+ pw.println("mWpsMetrics.numWpsOtherConnectionFailure="
+ + mWpsMetrics.numWpsOtherConnectionFailure);
+ pw.println("mWpsMetrics.numWpsSupplicantFailure="
+ + mWpsMetrics.numWpsSupplicantFailure);
+ pw.println("mWpsMetrics.numWpsCancellation="
+ + mWpsMetrics.numWpsCancellation);
}
}
}
@@ -1818,6 +2074,34 @@
mNumOpenNetworkRecommendationUpdates;
mWifiLogProto.numOpenNetworkConnectMessageFailedToSend =
mNumOpenNetworkConnectMessageFailedToSend;
+
+ mWifiLogProto.observedHotspotR1ApsInScanHistogram =
+ makeNumConnectableNetworksBucketArray(mObservedHotspotR1ApInScanHistogram);
+ mWifiLogProto.observedHotspotR2ApsInScanHistogram =
+ makeNumConnectableNetworksBucketArray(mObservedHotspotR2ApInScanHistogram);
+ mWifiLogProto.observedHotspotR1EssInScanHistogram =
+ makeNumConnectableNetworksBucketArray(mObservedHotspotR1EssInScanHistogram);
+ mWifiLogProto.observedHotspotR2EssInScanHistogram =
+ makeNumConnectableNetworksBucketArray(mObservedHotspotR2EssInScanHistogram);
+ mWifiLogProto.observedHotspotR1ApsPerEssInScanHistogram =
+ makeNumConnectableNetworksBucketArray(
+ mObservedHotspotR1ApsPerEssInScanHistogram);
+ mWifiLogProto.observedHotspotR2ApsPerEssInScanHistogram =
+ makeNumConnectableNetworksBucketArray(
+ mObservedHotspotR2ApsPerEssInScanHistogram);
+
+ if (mSoftApEventListTethered.size() > 0) {
+ mWifiLogProto.softApConnectedClientsEventsTethered =
+ mSoftApEventListTethered.toArray(
+ mWifiLogProto.softApConnectedClientsEventsTethered);
+ }
+ if (mSoftApEventListLocalOnly.size() > 0) {
+ mWifiLogProto.softApConnectedClientsEventsLocalOnly =
+ mSoftApEventListLocalOnly.toArray(
+ mWifiLogProto.softApConnectedClientsEventsLocalOnly);
+ }
+
+ mWifiLogProto.wpsMetrics = mWpsMetrics;
}
}
@@ -1872,6 +2156,15 @@
mConnectToNetworkNotificationActionCount.clear();
mNumOpenNetworkRecommendationUpdates = 0;
mNumOpenNetworkConnectMessageFailedToSend = 0;
+ mObservedHotspotR1ApInScanHistogram.clear();
+ mObservedHotspotR2ApInScanHistogram.clear();
+ mObservedHotspotR1EssInScanHistogram.clear();
+ mObservedHotspotR2EssInScanHistogram.clear();
+ mObservedHotspotR1ApsPerEssInScanHistogram.clear();
+ mObservedHotspotR2ApsPerEssInScanHistogram.clear();
+ mSoftApEventListTethered.clear();
+ mSoftApEventListLocalOnly.clear();
+ mWpsMetrics.clear();
}
}
@@ -1890,6 +2183,7 @@
public void setWifiState(int wifiState) {
synchronized (mLock) {
mWifiState = wifiState;
+ mWifiWins = (wifiState == WifiMetricsProto.WifiLog.WIFI_ASSOCIATED);
}
}
@@ -1995,6 +2289,7 @@
case StaEvent.TYPE_CONNECT_NETWORK:
case StaEvent.TYPE_NETWORK_AGENT_VALID_NETWORK:
case StaEvent.TYPE_FRAMEWORK_DISCONNECT:
+ case StaEvent.TYPE_SCORE_BREACH:
break;
default:
Log.e(TAG, "Unknown StaEvent:" + type);
@@ -2015,10 +2310,12 @@
staEvent.lastFreq = mLastPollFreq;
staEvent.lastLinkSpeed = mLastPollLinkSpeed;
staEvent.supplicantStateChangesBitmask = mSupplicantStateChangeBitmask;
+ staEvent.lastScore = mLastScore;
mSupplicantStateChangeBitmask = 0;
mLastPollRssi = -127;
mLastPollFreq = -1;
mLastPollLinkSpeed = -1;
+ mLastScore = -1;
mStaEventList.add(new StaEventWithTime(staEvent, mClock.getWallClockMillis()));
// Prune StaEventList if it gets too long
if (mStaEventList.size() > MAX_STA_EVENTS) mStaEventList.remove();
@@ -2174,6 +2471,9 @@
.append(" reason=")
.append(frameworkDisconnectReasonToString(event.frameworkDisconnectReason));
break;
+ case StaEvent.TYPE_SCORE_BREACH:
+ sb.append("SCORE_BREACH");
+ break;
default:
sb.append("UNKNOWN " + event.type + ":");
break;
@@ -2181,6 +2481,7 @@
if (event.lastRssi != -127) sb.append(" lastRssi=").append(event.lastRssi);
if (event.lastFreq != -1) sb.append(" lastFreq=").append(event.lastFreq);
if (event.lastLinkSpeed != -1) sb.append(" lastLinkSpeed=").append(event.lastLinkSpeed);
+ if (event.lastScore != -1) sb.append(" lastScore=").append(event.lastScore);
if (event.supplicantStateChangesBitmask != 0) {
sb.append(", ").append(supplicantStateChangesBitmaskToString(
event.supplicantStateChangesBitmask));
@@ -2243,11 +2544,12 @@
return sb.toString();
}
- public static final int MAX_STA_EVENTS = 512;
+ public static final int MAX_STA_EVENTS = 768;
private LinkedList<StaEventWithTime> mStaEventList = new LinkedList<StaEventWithTime>();
private int mLastPollRssi = -127;
private int mLastPollLinkSpeed = -1;
private int mLastPollFreq = -1;
+ private int mLastScore = -1;
/**
* Converts the first 31 bits of a BitSet to a little endian int
@@ -2272,6 +2574,15 @@
private void incrementTotalScanSsids(SparseIntArray sia, int element) {
increment(sia, Math.min(element, MAX_TOTAL_SCAN_RESULT_SSIDS_BUCKET));
}
+ private void incrementTotalPasspointAps(SparseIntArray sia, int element) {
+ increment(sia, Math.min(element, MAX_TOTAL_PASSPOINT_APS_BUCKET));
+ }
+ private void incrementTotalUniquePasspointEss(SparseIntArray sia, int element) {
+ increment(sia, Math.min(element, MAX_TOTAL_PASSPOINT_UNIQUE_ESS_BUCKET));
+ }
+ private void incrementPasspointPerUniqueEss(SparseIntArray sia, int element) {
+ increment(sia, Math.min(element, MAX_PASSPOINT_APS_PER_UNIQUE_ESS_BUCKET));
+ }
private void increment(SparseIntArray sia, int element) {
int count = sia.get(element);
sia.put(element, count + 1);
diff --git a/service/java/com/android/server/wifi/WifiNative.java b/service/java/com/android/server/wifi/WifiNative.java
index 5b12a36..fc815f8 100644
--- a/service/java/com/android/server/wifi/WifiNative.java
+++ b/service/java/com/android/server/wifi/WifiNative.java
@@ -16,6 +16,7 @@
package com.android.server.wifi;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.net.apf.ApfCapabilities;
import android.net.wifi.IApInterface;
@@ -105,12 +106,12 @@
* @return Pair of <Integer, IClientInterface> to indicate the status and the associated wificond
* client interface binder handler (will be null on failure).
*/
- public Pair<Integer, IClientInterface> setupForClientMode() {
+ public Pair<Integer, IClientInterface> setupForClientMode(@NonNull String ifaceName) {
if (!startHalIfNecessary(true)) {
Log.e(mTAG, "Failed to start HAL for client mode");
return Pair.create(SETUP_FAILURE_HAL, null);
}
- IClientInterface iClientInterface = mWificondControl.setupDriverForClientMode();
+ IClientInterface iClientInterface = mWificondControl.setupInterfaceForClientMode(ifaceName);
if (iClientInterface == null) {
return Pair.create(SETUP_FAILURE_WIFICOND, null);
}
@@ -126,12 +127,12 @@
* @return Pair of <Integer, IApInterface> to indicate the status and the associated wificond
* AP interface binder handler (will be null on failure).
*/
- public Pair<Integer, IApInterface> setupForSoftApMode() {
+ public Pair<Integer, IApInterface> setupForSoftApMode(@NonNull String ifaceName) {
if (!startHalIfNecessary(false)) {
Log.e(mTAG, "Failed to start HAL for AP mode");
return Pair.create(SETUP_FAILURE_HAL, null);
}
- IApInterface iApInterface = mWificondControl.setupDriverForSoftApMode();
+ IApInterface iApInterface = mWificondControl.setupInterfaceForSoftApMode(ifaceName);
if (iApInterface == null) {
return Pair.create(SETUP_FAILURE_WIFICOND, null);
}
@@ -178,6 +179,32 @@
}
/**
+ * Callback to notify wificond death.
+ */
+ public interface WificondDeathEventHandler {
+ /**
+ * Invoked when the wificond dies.
+ */
+ void onDeath();
+ }
+
+ /**
+ * Registers a death notification for wificond.
+ * @return Returns true on success.
+ */
+ public boolean registerWificondDeathHandler(@NonNull WificondDeathEventHandler handler) {
+ return mWificondControl.registerDeathHandler(handler);
+ }
+
+ /**
+ * Deregisters a death notification for wificond.
+ * @return Returns true on success.
+ */
+ public boolean deregisterWificondDeathHandler() {
+ return mWificondControl.deregisterDeathHandler();
+ }
+
+ /**
* Disable wpa_supplicant via wificond.
* @return Returns true on success.
*/
@@ -199,7 +226,7 @@
* Returns null on failure.
*/
public SignalPollResult signalPoll() {
- return mWificondControl.signalPoll();
+ return mWificondControl.signalPoll(mInterfaceName);
}
/**
@@ -208,7 +235,23 @@
* Returns null on failure.
*/
public TxPacketCounters getTxPacketCounters() {
- return mWificondControl.getTxPacketCounters();
+ return mWificondControl.getTxPacketCounters(mInterfaceName);
+ }
+
+ /**
+ * Query the list of valid frequencies 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.
+ * The following bands are supported:
+ * WifiScanner.WIFI_BAND_24_GHZ
+ * WifiScanner.WIFI_BAND_5_GHZ
+ * WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY
+ * @return frequencies vector of valid frequencies (MHz), or null for error.
+ * @throws IllegalArgumentException if band is not recognized.
+ */
+ public int [] getChannelsForBand(int band) {
+ return mWificondControl.getChannelsForBand(band);
}
/**
@@ -218,7 +261,7 @@
* @return Returns true on success.
*/
public boolean scan(Set<Integer> freqs, Set<String> hiddenNetworkSSIDs) {
- return mWificondControl.scan(freqs, hiddenNetworkSSIDs);
+ return mWificondControl.scan(mInterfaceName, freqs, hiddenNetworkSSIDs);
}
/**
@@ -227,7 +270,8 @@
* Returns an empty ArrayList on failure.
*/
public ArrayList<ScanDetail> getScanResults() {
- return mWificondControl.getScanResults(WificondControl.SCAN_TYPE_SINGLE_SCAN);
+ return mWificondControl.getScanResults(
+ mInterfaceName, WificondControl.SCAN_TYPE_SINGLE_SCAN);
}
/**
@@ -236,7 +280,7 @@
* Returns an empty ArrayList on failure.
*/
public ArrayList<ScanDetail> getPnoScanResults() {
- return mWificondControl.getScanResults(WificondControl.SCAN_TYPE_PNO_SCAN);
+ return mWificondControl.getScanResults(mInterfaceName, WificondControl.SCAN_TYPE_PNO_SCAN);
}
/**
@@ -245,7 +289,7 @@
* @return true on success.
*/
public boolean startPnoScan(PnoSettings pnoSettings) {
- return mWificondControl.startPnoScan(pnoSettings);
+ return mWificondControl.startPnoScan(mInterfaceName, pnoSettings);
}
/**
@@ -253,7 +297,37 @@
* @return true on success.
*/
public boolean stopPnoScan() {
- return mWificondControl.stopPnoScan();
+ return mWificondControl.stopPnoScan(mInterfaceName);
+ }
+
+ /**
+ * Callbacks for SoftAp interface.
+ */
+ public interface SoftApListener {
+ /**
+ * Invoked when the number of associated stations changes.
+ */
+ void onNumAssociatedStationsChanged(int numStations);
+ }
+
+ /**
+ * Start Soft AP operation using the provided configuration.
+ *
+ * @param config Configuration to use for the soft ap created.
+ * @param listener Callback for AP events.
+ * @return true on success, false otherwise.
+ */
+ public boolean startSoftAp(WifiConfiguration config, SoftApListener listener) {
+ return mWificondControl.startSoftAp(mInterfaceName, config, listener);
+ }
+
+ /**
+ * Stop the ongoing Soft AP operation.
+ *
+ * @return true on success, false otherwise.
+ */
+ public boolean stopSoftAp() {
+ return mWificondControl.stopSoftAp(mInterfaceName);
}
/********************************************************
@@ -261,7 +335,26 @@
********************************************************/
/**
- * This method is called repeatedly until the connection to wpa_supplicant is established.
+ * Callback to notify supplicant death.
+ */
+ public interface SupplicantDeathEventHandler {
+ /**
+ * Invoked when the supplicant dies.
+ */
+ void onDeath();
+ }
+
+ /**
+ * Registers a death notification for supplicant.
+ * @return Returns true on success.
+ */
+ public boolean registerSupplicantDeathHandler(@NonNull SupplicantDeathEventHandler handler) {
+ return mSupplicantStaIfaceHal.registerDeathHandler(handler);
+ }
+
+ /**
+ * This method is called repeatedly until the connection to wpa_supplicant is
+ * established and a STA iface is setup.
*
* @return true if connection is established, false otherwise.
* TODO: Add unit tests for these once we remove the legacy code.
@@ -273,14 +366,19 @@
return false;
}
// Check if the initialization is complete.
- return mSupplicantStaIfaceHal.isInitializationComplete();
+ if (!mSupplicantStaIfaceHal.isInitializationComplete()) {
+ return false;
+ }
+ // Setup the STA iface once connection is established.
+ return mSupplicantStaIfaceHal.setupIface(mInterfaceName);
}
/**
* Close supplicant connection.
*/
public void closeSupplicantConnection() {
- // Nothing to do for HIDL.
+ // Setup the STA iface once connection is established.
+ mSupplicantStaIfaceHal.teardownIface(mInterfaceName);
}
/**
@@ -298,7 +396,7 @@
* @return true if request is sent successfully, false otherwise.
*/
public boolean reconnect() {
- return mSupplicantStaIfaceHal.reconnect();
+ return mSupplicantStaIfaceHal.reconnect(mInterfaceName);
}
/**
@@ -307,7 +405,7 @@
* @return true if request is sent successfully, false otherwise.
*/
public boolean reassociate() {
- return mSupplicantStaIfaceHal.reassociate();
+ return mSupplicantStaIfaceHal.reassociate(mInterfaceName);
}
/**
@@ -316,7 +414,7 @@
* @return true if request is sent successfully, false otherwise.
*/
public boolean disconnect() {
- return mSupplicantStaIfaceHal.disconnect();
+ return mSupplicantStaIfaceHal.disconnect(mInterfaceName);
}
/**
@@ -325,7 +423,7 @@
* @return string containing the MAC address, or null on a failed call
*/
public String getMacAddress() {
- return mSupplicantStaIfaceHal.getMacAddress();
+ return mSupplicantStaIfaceHal.getMacAddress(mInterfaceName);
}
public static final int RX_FILTER_TYPE_V4_MULTICAST = 0;
@@ -355,10 +453,10 @@
* The SETSUSPENDOPT driver command overrides the filtering rules
*/
public boolean startFilteringMulticastV4Packets() {
- return mSupplicantStaIfaceHal.stopRxFilter()
+ return mSupplicantStaIfaceHal.stopRxFilter(mInterfaceName)
&& mSupplicantStaIfaceHal.removeRxFilter(
- RX_FILTER_TYPE_V4_MULTICAST)
- && mSupplicantStaIfaceHal.startRxFilter();
+ mInterfaceName, RX_FILTER_TYPE_V4_MULTICAST)
+ && mSupplicantStaIfaceHal.startRxFilter(mInterfaceName);
}
/**
@@ -366,10 +464,10 @@
* @return {@code true} if the operation succeeded, {@code false} otherwise
*/
public boolean stopFilteringMulticastV4Packets() {
- return mSupplicantStaIfaceHal.stopRxFilter()
+ return mSupplicantStaIfaceHal.stopRxFilter(mInterfaceName)
&& mSupplicantStaIfaceHal.addRxFilter(
- RX_FILTER_TYPE_V4_MULTICAST)
- && mSupplicantStaIfaceHal.startRxFilter();
+ mInterfaceName, RX_FILTER_TYPE_V4_MULTICAST)
+ && mSupplicantStaIfaceHal.startRxFilter(mInterfaceName);
}
/**
@@ -377,10 +475,10 @@
* @return {@code true} if the operation succeeded, {@code false} otherwise
*/
public boolean startFilteringMulticastV6Packets() {
- return mSupplicantStaIfaceHal.stopRxFilter()
+ return mSupplicantStaIfaceHal.stopRxFilter(mInterfaceName)
&& mSupplicantStaIfaceHal.removeRxFilter(
- RX_FILTER_TYPE_V6_MULTICAST)
- && mSupplicantStaIfaceHal.startRxFilter();
+ mInterfaceName, RX_FILTER_TYPE_V6_MULTICAST)
+ && mSupplicantStaIfaceHal.startRxFilter(mInterfaceName);
}
/**
@@ -388,10 +486,10 @@
* @return {@code true} if the operation succeeded, {@code false} otherwise
*/
public boolean stopFilteringMulticastV6Packets() {
- return mSupplicantStaIfaceHal.stopRxFilter()
+ return mSupplicantStaIfaceHal.stopRxFilter(mInterfaceName)
&& mSupplicantStaIfaceHal.addRxFilter(
- RX_FILTER_TYPE_V6_MULTICAST)
- && mSupplicantStaIfaceHal.startRxFilter();
+ mInterfaceName, RX_FILTER_TYPE_V6_MULTICAST)
+ && mSupplicantStaIfaceHal.startRxFilter(mInterfaceName);
}
public static final int BLUETOOTH_COEXISTENCE_MODE_ENABLED = 0;
@@ -406,7 +504,7 @@
* @return Whether the mode was successfully set.
*/
public boolean setBluetoothCoexistenceMode(int mode) {
- return mSupplicantStaIfaceHal.setBtCoexistenceMode(mode);
+ return mSupplicantStaIfaceHal.setBtCoexistenceMode(mInterfaceName, mode);
}
/**
@@ -418,7 +516,8 @@
* @return {@code true} if the command succeeded, {@code false} otherwise.
*/
public boolean setBluetoothCoexistenceScanMode(boolean setCoexScanMode) {
- return mSupplicantStaIfaceHal.setBtCoexistenceScanModeEnabled(setCoexScanMode);
+ return mSupplicantStaIfaceHal.setBtCoexistenceScanModeEnabled(
+ mInterfaceName, setCoexScanMode);
}
/**
@@ -428,7 +527,7 @@
* @return true if request is sent successfully, false otherwise.
*/
public boolean setSuspendOptimizations(boolean enabled) {
- return mSupplicantStaIfaceHal.setSuspendModeEnabled(enabled);
+ return mSupplicantStaIfaceHal.setSuspendModeEnabled(mInterfaceName, enabled);
}
/**
@@ -438,7 +537,7 @@
* @return true if request is sent successfully, false otherwise.
*/
public boolean setCountryCode(String countryCode) {
- return mSupplicantStaIfaceHal.setCountryCode(countryCode);
+ return mSupplicantStaIfaceHal.setCountryCode(mInterfaceName, countryCode);
}
/**
@@ -449,10 +548,10 @@
*/
public void startTdls(String macAddr, boolean enable) {
if (enable) {
- mSupplicantStaIfaceHal.initiateTdlsDiscover(macAddr);
- mSupplicantStaIfaceHal.initiateTdlsSetup(macAddr);
+ mSupplicantStaIfaceHal.initiateTdlsDiscover(mInterfaceName, macAddr);
+ mSupplicantStaIfaceHal.initiateTdlsSetup(mInterfaceName, macAddr);
} else {
- mSupplicantStaIfaceHal.initiateTdlsTeardown(macAddr);
+ mSupplicantStaIfaceHal.initiateTdlsTeardown(mInterfaceName, macAddr);
}
}
@@ -463,7 +562,7 @@
* @return true if request is sent successfully, false otherwise.
*/
public boolean startWpsPbc(String bssid) {
- return mSupplicantStaIfaceHal.startWpsPbc(bssid);
+ return mSupplicantStaIfaceHal.startWpsPbc(mInterfaceName, bssid);
}
/**
@@ -473,7 +572,7 @@
* @return true if request is sent successfully, false otherwise.
*/
public boolean startWpsPinKeypad(String pin) {
- return mSupplicantStaIfaceHal.startWpsPinKeypad(pin);
+ return mSupplicantStaIfaceHal.startWpsPinKeypad(mInterfaceName, pin);
}
/**
@@ -483,7 +582,7 @@
* @return new pin generated on success, null otherwise.
*/
public String startWpsPinDisplay(String bssid) {
- return mSupplicantStaIfaceHal.startWpsPinDisplay(bssid);
+ return mSupplicantStaIfaceHal.startWpsPinDisplay(mInterfaceName, bssid);
}
/**
@@ -493,7 +592,7 @@
* @return true if request is sent successfully, false otherwise.
*/
public boolean setExternalSim(boolean external) {
- return mSupplicantStaIfaceHal.setExternalSim(external);
+ return mSupplicantStaIfaceHal.setExternalSim(mInterfaceName, external);
}
/**
@@ -512,11 +611,14 @@
*/
public boolean simAuthResponse(int id, String type, String response) {
if (SIM_AUTH_RESP_TYPE_GSM_AUTH.equals(type)) {
- return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimGsmAuthResponse(response);
+ return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimGsmAuthResponse(
+ mInterfaceName, response);
} else if (SIM_AUTH_RESP_TYPE_UMTS_AUTH.equals(type)) {
- return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimUmtsAuthResponse(response);
+ return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimUmtsAuthResponse(
+ mInterfaceName, response);
} else if (SIM_AUTH_RESP_TYPE_UMTS_AUTS.equals(type)) {
- return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimUmtsAutsResponse(response);
+ return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimUmtsAutsResponse(
+ mInterfaceName, response);
} else {
return false;
}
@@ -528,7 +630,7 @@
* @return true if succeeds, false otherwise.
*/
public boolean simAuthFailedResponse(int id) {
- return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimGsmAuthFailure();
+ return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimGsmAuthFailure(mInterfaceName);
}
/**
@@ -537,7 +639,7 @@
* @return true if succeeds, false otherwise.
*/
public boolean umtsAuthFailedResponse(int id) {
- return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimUmtsAuthFailure();
+ return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimUmtsAuthFailure(mInterfaceName);
}
/**
@@ -547,7 +649,8 @@
* @return true if succeeds, false otherwise.
*/
public boolean simIdentityResponse(int id, String response) {
- return mSupplicantStaIfaceHal.sendCurrentNetworkEapIdentityResponse(response);
+ return mSupplicantStaIfaceHal.sendCurrentNetworkEapIdentityResponse(
+ mInterfaceName, response);
}
/**
@@ -556,7 +659,7 @@
* @return anonymous identity string if succeeds, null otherwise.
*/
public String getEapAnonymousIdentity() {
- return mSupplicantStaIfaceHal.getCurrentNetworkEapAnonymousIdentity();
+ return mSupplicantStaIfaceHal.getCurrentNetworkEapAnonymousIdentity(mInterfaceName);
}
/**
@@ -567,7 +670,7 @@
* @return true if request is sent successfully, false otherwise.
*/
public boolean startWpsRegistrar(String bssid, String pin) {
- return mSupplicantStaIfaceHal.startWpsRegistrar(bssid, pin);
+ return mSupplicantStaIfaceHal.startWpsRegistrar(mInterfaceName, bssid, pin);
}
/**
@@ -576,7 +679,7 @@
* @return true if request is sent successfully, false otherwise.
*/
public boolean cancelWps() {
- return mSupplicantStaIfaceHal.cancelWps();
+ return mSupplicantStaIfaceHal.cancelWps(mInterfaceName);
}
/**
@@ -586,7 +689,7 @@
* @return true if request is sent successfully, false otherwise.
*/
public boolean setDeviceName(String name) {
- return mSupplicantStaIfaceHal.setWpsDeviceName(name);
+ return mSupplicantStaIfaceHal.setWpsDeviceName(mInterfaceName, name);
}
/**
@@ -596,7 +699,7 @@
* @return true if request is sent successfully, false otherwise.
*/
public boolean setDeviceType(String type) {
- return mSupplicantStaIfaceHal.setWpsDeviceType(type);
+ return mSupplicantStaIfaceHal.setWpsDeviceType(mInterfaceName, type);
}
/**
@@ -606,7 +709,7 @@
* @return true if request is sent successfully, false otherwise.
*/
public boolean setConfigMethods(String cfg) {
- return mSupplicantStaIfaceHal.setWpsConfigMethods(cfg);
+ return mSupplicantStaIfaceHal.setWpsConfigMethods(mInterfaceName, cfg);
}
/**
@@ -616,7 +719,7 @@
* @return true if request is sent successfully, false otherwise.
*/
public boolean setManufacturer(String value) {
- return mSupplicantStaIfaceHal.setWpsManufacturer(value);
+ return mSupplicantStaIfaceHal.setWpsManufacturer(mInterfaceName, value);
}
/**
@@ -626,7 +729,7 @@
* @return true if request is sent successfully, false otherwise.
*/
public boolean setModelName(String value) {
- return mSupplicantStaIfaceHal.setWpsModelName(value);
+ return mSupplicantStaIfaceHal.setWpsModelName(mInterfaceName, value);
}
/**
@@ -636,7 +739,7 @@
* @return true if request is sent successfully, false otherwise.
*/
public boolean setModelNumber(String value) {
- return mSupplicantStaIfaceHal.setWpsModelNumber(value);
+ return mSupplicantStaIfaceHal.setWpsModelNumber(mInterfaceName, value);
}
/**
@@ -646,7 +749,7 @@
* @return true if request is sent successfully, false otherwise.
*/
public boolean setSerialNumber(String value) {
- return mSupplicantStaIfaceHal.setWpsSerialNumber(value);
+ return mSupplicantStaIfaceHal.setWpsSerialNumber(mInterfaceName, value);
}
/**
@@ -655,7 +758,7 @@
* @param enabled true to enable, false to disable.
*/
public void setPowerSave(boolean enabled) {
- mSupplicantStaIfaceHal.setPowerSave(enabled);
+ mSupplicantStaIfaceHal.setPowerSave(mInterfaceName, enabled);
}
/**
@@ -676,7 +779,7 @@
* @return true if request is sent successfully, false otherwise.
*/
public boolean enableStaAutoReconnect(boolean enable) {
- return mSupplicantStaIfaceHal.enableAutoReconnect(enable);
+ return mSupplicantStaIfaceHal.enableAutoReconnect(mInterfaceName, enable);
}
/**
@@ -689,7 +792,7 @@
*/
public boolean migrateNetworksFromSupplicant(Map<String, WifiConfiguration> configs,
SparseArray<Map<String, String>> networkExtras) {
- return mSupplicantStaIfaceHal.loadNetworks(configs, networkExtras);
+ return mSupplicantStaIfaceHal.loadNetworks(mInterfaceName, configs, networkExtras);
}
/**
@@ -707,8 +810,8 @@
*/
public boolean connectToNetwork(WifiConfiguration configuration) {
// Abort ongoing scan before connect() to unblock connection request.
- mWificondControl.abortScan();
- return mSupplicantStaIfaceHal.connectToNetwork(configuration);
+ mWificondControl.abortScan(mInterfaceName);
+ return mSupplicantStaIfaceHal.connectToNetwork(mInterfaceName, configuration);
}
/**
@@ -726,8 +829,8 @@
*/
public boolean roamToNetwork(WifiConfiguration configuration) {
// Abort ongoing scan before connect() to unblock roaming request.
- mWificondControl.abortScan();
- return mSupplicantStaIfaceHal.roamToNetwork(configuration);
+ mWificondControl.abortScan(mInterfaceName);
+ return mSupplicantStaIfaceHal.roamToNetwork(mInterfaceName, configuration);
}
/**
@@ -747,7 +850,7 @@
* @return {@code true} if it succeeds, {@code false} otherwise
*/
public boolean removeAllNetworks() {
- return mSupplicantStaIfaceHal.removeAllNetworks();
+ return mSupplicantStaIfaceHal.removeAllNetworks(mInterfaceName);
}
/**
@@ -756,7 +859,7 @@
* @return true if successful, false otherwise.
*/
public boolean setConfiguredNetworkBSSID(String bssid) {
- return mSupplicantStaIfaceHal.setCurrentNetworkBssid(bssid);
+ return mSupplicantStaIfaceHal.setCurrentNetworkBssid(mInterfaceName, bssid);
}
/**
@@ -779,7 +882,8 @@
}
ArrayList<Integer> hs20SubtypeList = new ArrayList<>();
hs20SubtypeList.addAll(hs20Subtypes);
- return mSupplicantStaIfaceHal.initiateAnqpQuery(bssid, anqpIdList, hs20SubtypeList);
+ return mSupplicantStaIfaceHal.initiateAnqpQuery(
+ mInterfaceName, bssid, anqpIdList, hs20SubtypeList);
}
/**
@@ -793,7 +897,7 @@
Log.e(mTAG, "Invalid arguments for Icon request.");
return false;
}
- return mSupplicantStaIfaceHal.initiateHs20IconQuery(bssid, fileName);
+ return mSupplicantStaIfaceHal.initiateHs20IconQuery(mInterfaceName, bssid, fileName);
}
/**
@@ -802,7 +906,7 @@
* @return Hex string corresponding to the WPS NFC token.
*/
public String getCurrentNetworkWpsNfcConfigurationToken() {
- return mSupplicantStaIfaceHal.getCurrentNetworkWpsNfcConfigurationToken();
+ return mSupplicantStaIfaceHal.getCurrentNetworkWpsNfcConfigurationToken(mInterfaceName);
}
/** Remove the request |networkId| from supplicant if it's the current network,
@@ -811,7 +915,7 @@
* @param networkId network id of the network to be removed from supplicant.
*/
public void removeNetworkIfCurrent(int networkId) {
- mSupplicantStaIfaceHal.removeNetworkIfCurrent(networkId);
+ mSupplicantStaIfaceHal.removeNetworkIfCurrent(mInterfaceName, networkId);
}
/********************************************************
@@ -845,7 +949,11 @@
Log.i(mTAG, "Vendor HAL not supported, Ignore start...");
return true;
}
- return mWifiVendorHal.startVendorHal(isStaMode);
+ if (isStaMode) {
+ return mWifiVendorHal.startVendorHalSta();
+ } else {
+ return mWifiVendorHal.startVendorHalAp();
+ }
}
/**
@@ -882,7 +990,7 @@
* @return true for success. false for failure
*/
public boolean getBgScanCapabilities(ScanCapabilities capabilities) {
- return mWifiVendorHal.getBgScanCapabilities(capabilities);
+ return mWifiVendorHal.getBgScanCapabilities(mInterfaceName, capabilities);
}
public static class ChannelSettings {
@@ -1032,39 +1140,39 @@
* @return true for success
*/
public boolean startBgScan(ScanSettings settings, ScanEventHandler eventHandler) {
- return mWifiVendorHal.startBgScan(settings, eventHandler);
+ return mWifiVendorHal.startBgScan(mInterfaceName, settings, eventHandler);
}
/**
* Stops any ongoing backgound scan
*/
public void stopBgScan() {
- mWifiVendorHal.stopBgScan();
+ mWifiVendorHal.stopBgScan(mInterfaceName);
}
/**
* Pauses an ongoing backgound scan
*/
public void pauseBgScan() {
- mWifiVendorHal.pauseBgScan();
+ mWifiVendorHal.pauseBgScan(mInterfaceName);
}
/**
* Restarts a paused scan
*/
public void restartBgScan() {
- mWifiVendorHal.restartBgScan();
+ mWifiVendorHal.restartBgScan(mInterfaceName);
}
/**
* Gets the latest scan results received.
*/
public WifiScanner.ScanData[] getBgScanResults() {
- return mWifiVendorHal.getBgScanResults();
+ return mWifiVendorHal.getBgScanResults(mInterfaceName);
}
- public WifiLinkLayerStats getWifiLinkLayerStats(String iface) {
- return mWifiVendorHal.getWifiLinkLayerStats();
+ public WifiLinkLayerStats getWifiLinkLayerStats() {
+ return mWifiVendorHal.getWifiLinkLayerStats(mInterfaceName);
}
/**
@@ -1073,7 +1181,7 @@
* @return bitmask defined by WifiManager.WIFI_FEATURE_*
*/
public int getSupportedFeatureSet() {
- return mWifiVendorHal.getSupportedFeatureSet();
+ return mWifiVendorHal.getSupportedFeatureSet(mInterfaceName);
}
public static interface RttEventHandler {
@@ -1130,28 +1238,7 @@
* @return true for success
*/
public boolean setScanningMacOui(byte[] oui) {
- return mWifiVendorHal.setScanningMacOui(oui);
- }
-
- /**
- * Query the list of valid frequencies 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.
- * @return frequencies vector of valid frequencies (MHz), or null for error.
- * @throws IllegalArgumentException if band is not recognized.
- */
- public int [] getChannelsForBand(int band) {
- return mWifiVendorHal.getChannelsForBand(band);
- }
-
- /**
- * Indicates whether getChannelsForBand is supported.
- *
- * @return true if it is.
- */
- public boolean isGetChannelsForBandSupported() {
- return mWifiVendorHal.isGetChannelsForBandSupported();
+ return mWifiVendorHal.setScanningMacOui(mInterfaceName, oui);
}
/**
@@ -1165,7 +1252,7 @@
* Get the APF (Android Packet Filter) capabilities of the device
*/
public ApfCapabilities getApfCapabilities() {
- return mWifiVendorHal.getApfCapabilities();
+ return mWifiVendorHal.getApfCapabilities(mInterfaceName);
}
/**
@@ -1175,7 +1262,7 @@
* @return true for success
*/
public boolean installPacketFilter(byte[] filter) {
- return mWifiVendorHal.installPacketFilter(filter);
+ return mWifiVendorHal.installPacketFilter(mInterfaceName, filter);
}
/**
@@ -1185,7 +1272,7 @@
* @return true for success
*/
public boolean setCountryCodeHal(String countryCode) {
- return mWifiVendorHal.setCountryCodeHal(countryCode);
+ return mWifiVendorHal.setCountryCodeHal(mInterfaceName, countryCode);
}
//---------------------------------------------------------------------------------
@@ -1525,7 +1612,7 @@
* @return true for success, false otherwise.
*/
public boolean startPktFateMonitoring() {
- return mWifiVendorHal.startPktFateMonitoring();
+ return mWifiVendorHal.startPktFateMonitoring(mInterfaceName);
}
/**
@@ -1534,14 +1621,14 @@
* @return true for success, false otherwise.
*/
public boolean getTxPktFates(TxFateReport[] reportBufs) {
- return mWifiVendorHal.getTxPktFates(reportBufs);
+ return mWifiVendorHal.getTxPktFates(mInterfaceName, reportBufs);
}
/**
* Fetch the most recent RX packet fates from the HAL. Fails unless HAL is started.
*/
public boolean getRxPktFates(RxFateReport[] reportBufs) {
- return mWifiVendorHal.getRxPktFates(reportBufs);
+ return mWifiVendorHal.getRxPktFates(mInterfaceName, reportBufs);
}
/**
@@ -1560,7 +1647,7 @@
Integer hexVal = Integer.parseInt(macAddrStr[i], 16);
srcMac[i] = hexVal.byteValue();
}
- return mWifiVendorHal.startSendingOffloadedPacket(
+ return mWifiVendorHal.startSendingOffloadedPacket(mInterfaceName,
slot, srcMac, keepAlivePacket, period);
}
@@ -1571,7 +1658,7 @@
* @return 0 for success, -1 for error
*/
public int stopSendingOffloadedPacket(int slot) {
- return mWifiVendorHal.stopSendingOffloadedPacket(slot);
+ return mWifiVendorHal.stopSendingOffloadedPacket(mInterfaceName, slot);
}
public static interface WifiRssiEventHandler {
@@ -1588,11 +1675,12 @@
*/
public int startRssiMonitoring(byte maxRssi, byte minRssi,
WifiRssiEventHandler rssiEventHandler) {
- return mWifiVendorHal.startRssiMonitoring(maxRssi, minRssi, rssiEventHandler);
+ return mWifiVendorHal.startRssiMonitoring(
+ mInterfaceName, maxRssi, minRssi, rssiEventHandler);
}
public int stopRssiMonitoring() {
- return mWifiVendorHal.stopRssiMonitoring();
+ return mWifiVendorHal.stopRssiMonitoring(mInterfaceName);
}
/**
@@ -1611,7 +1699,7 @@
* @return true for success, false otherwise.
*/
public boolean configureNeighborDiscoveryOffload(boolean enabled) {
- return mWifiVendorHal.configureNeighborDiscoveryOffload(enabled);
+ return mWifiVendorHal.configureNeighborDiscoveryOffload(mInterfaceName, enabled);
}
// Firmware roaming control.
@@ -1629,7 +1717,7 @@
* @return true for success, false otherwise.
*/
public boolean getRoamingCapabilities(RoamingCapabilities capabilities) {
- return mWifiVendorHal.getRoamingCapabilities(capabilities);
+ return mWifiVendorHal.getRoamingCapabilities(mInterfaceName, capabilities);
}
/**
@@ -1644,7 +1732,7 @@
* @return error code returned from HAL.
*/
public int enableFirmwareRoaming(int state) {
- return mWifiVendorHal.enableFirmwareRoaming(state);
+ return mWifiVendorHal.enableFirmwareRoaming(mInterfaceName, state);
}
/**
@@ -1660,7 +1748,7 @@
*/
public boolean configureRoaming(RoamingConfig config) {
Log.d(mTAG, "configureRoaming ");
- return mWifiVendorHal.configureRoaming(config);
+ return mWifiVendorHal.configureRoaming(mInterfaceName, config);
}
/**
@@ -1669,7 +1757,7 @@
public boolean resetRoamingConfiguration() {
// Pass in an empty RoamingConfig object which translates to zero size
// blacklist and whitelist to reset the firmware roaming configuration.
- return mWifiVendorHal.configureRoaming(new RoamingConfig());
+ return mWifiVendorHal.configureRoaming(mInterfaceName, new RoamingConfig());
}
/**
diff --git a/service/java/com/android/server/wifi/WifiScoreReport.java b/service/java/com/android/server/wifi/WifiScoreReport.java
index 894d57c..e5281ef 100644
--- a/service/java/com/android/server/wifi/WifiScoreReport.java
+++ b/service/java/com/android/server/wifi/WifiScoreReport.java
@@ -49,11 +49,13 @@
ConnectedScore mConnectedScore;
ConnectedScore mAggressiveConnectedScore;
+ VelocityBasedConnectedScore mFancyConnectedScore;
WifiScoreReport(Context context, WifiConfigManager wifiConfigManager, Clock clock) {
mClock = clock;
mConnectedScore = new LegacyConnectedScore(context, wifiConfigManager, clock);
mAggressiveConnectedScore = new AggressiveConnectedScore(context, clock);
+ mFancyConnectedScore = new VelocityBasedConnectedScore(context, clock);
}
/**
@@ -76,6 +78,7 @@
}
mConnectedScore.reset();
mAggressiveConnectedScore.reset();
+ mFancyConnectedScore.reset();
if (mVerboseLoggingEnabled) Log.d(TAG, "reset");
}
@@ -113,18 +116,20 @@
int aggressiveHandover, WifiMetrics wifiMetrics) {
int score;
- long millis = mConnectedScore.getMillis();
+ long millis = mClock.getWallClockMillis();
mConnectedScore.updateUsingWifiInfo(wifiInfo, millis);
mAggressiveConnectedScore.updateUsingWifiInfo(wifiInfo, millis);
+ mFancyConnectedScore.updateUsingWifiInfo(wifiInfo, millis);
int s0 = mConnectedScore.generateScore();
int s1 = mAggressiveConnectedScore.generateScore();
+ int s2 = mFancyConnectedScore.generateScore();
if (aggressiveHandover == 0) {
- score = s0;
+ score = s2;
} else {
- score = s1;
+ score = s2; // TODO Remove aggressive handover plumbing (b/27877641)
}
//sanitize boundaries
@@ -135,7 +140,7 @@
score = 0;
}
- logLinkMetrics(wifiInfo, s0, s1);
+ logLinkMetrics(wifiInfo, millis, s0, s1, s2);
//report score
if (score != wifiInfo.score) {
@@ -163,29 +168,34 @@
/**
* Data logging for dumpsys
*/
- private void logLinkMetrics(WifiInfo wifiInfo, int s0, int s1) {
- long now = mClock.getWallClockMillis();
+ private void logLinkMetrics(WifiInfo wifiInfo, long now, int s0, int s1, int s2) {
if (now < FIRST_REASONABLE_WALL_CLOCK) return;
double rssi = wifiInfo.getRssi();
+ double filteredRssi = mFancyConnectedScore.getFilteredRssi();
+ double rssiThreshold = mFancyConnectedScore.getAdjustedRssiThreshold();
int freq = wifiInfo.getFrequency();
int linkSpeed = wifiInfo.getLinkSpeed();
double txSuccessRate = wifiInfo.txSuccessRate;
double txRetriesRate = wifiInfo.txRetriesRate;
double txBadRate = wifiInfo.txBadRate;
double rxSuccessRate = wifiInfo.rxSuccessRate;
+ String s;
try {
String timestamp = new SimpleDateFormat("MM-dd HH:mm:ss.SSS").format(new Date(now));
- String s = String.format(Locale.US, // Use US to avoid comma/decimal confusion
- "%s,%d,%.1f,%d,%d,%.2f,%.2f,%.2f,%.2f,%d,%d",
- timestamp, mSessionNumber, rssi, freq, linkSpeed,
+ s = String.format(Locale.US, // Use US to avoid comma/decimal confusion
+ "%s,%d,%.1f,%.1f,%.1f,%d,%d,%.2f,%.2f,%.2f,%.2f,%d,%d,%d",
+ timestamp, mSessionNumber, rssi, filteredRssi, rssiThreshold, freq, linkSpeed,
txSuccessRate, txRetriesRate, txBadRate, rxSuccessRate,
- s0, s1);
- mLinkMetricsHistory.add(s);
+ s0, s1, s2);
} catch (Exception e) {
Log.e(TAG, "format problem", e);
+ return;
}
- while (mLinkMetricsHistory.size() > DUMPSYS_ENTRY_COUNT_LIMIT) {
- mLinkMetricsHistory.removeFirst();
+ synchronized (mLinkMetricsHistory) {
+ mLinkMetricsHistory.add(s);
+ while (mLinkMetricsHistory.size() > DUMPSYS_ENTRY_COUNT_LIMIT) {
+ mLinkMetricsHistory.removeFirst();
+ }
}
}
@@ -201,9 +211,15 @@
* @param args unused
*/
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println("time,session,rssi,freq,linkspeed,tx_good,tx_retry,tx_bad,rx,s0,s1");
- for (String line : mLinkMetricsHistory) {
+ LinkedList<String> history;
+ synchronized (mLinkMetricsHistory) {
+ history = new LinkedList<>(mLinkMetricsHistory);
+ }
+ pw.println("time,session,rssi,filtered_rssi,rssi_threshold,"
+ + "freq,linkspeed,tx_good,tx_retry,tx_bad,rx,s0,s1,s2");
+ for (String line : history) {
pw.println(line);
}
+ history.clear();
}
}
diff --git a/service/java/com/android/server/wifi/WifiServiceImpl.java b/service/java/com/android/server/wifi/WifiServiceImpl.java
index d2f90e0..8db180f 100644
--- a/service/java/com/android/server/wifi/WifiServiceImpl.java
+++ b/service/java/com/android/server/wifi/WifiServiceImpl.java
@@ -73,6 +73,7 @@
import android.net.wifi.WifiManager;
import android.net.wifi.WifiManager.LocalOnlyHotspotCallback;
import android.net.wifi.WifiScanner;
+import android.net.wifi.hotspot2.IProvisioningCallback;
import android.net.wifi.hotspot2.OsuProvider;
import android.net.wifi.hotspot2.PasspointConfiguration;
import android.os.AsyncTask;
@@ -141,11 +142,6 @@
private static final boolean DBG = true;
private static final boolean VDBG = false;
- // Dumpsys argument to enable/disable disconnect on IP reachability failures.
- private static final String DUMP_ARG_SET_IPREACH_DISCONNECT = "set-ipreach-disconnect";
- private static final String DUMP_ARG_SET_IPREACH_DISCONNECT_ENABLED = "enabled";
- private static final String DUMP_ARG_SET_IPREACH_DISCONNECT_DISABLED = "disabled";
-
// Default scan background throttling interval if not overriden in settings
private static final long DEFAULT_SCAN_BACKGROUND_THROTTLE_INTERVAL_MS = 30 * 60 * 1000;
@@ -857,32 +853,6 @@
}
/**
- * see {@link android.net.wifi.WifiManager#setWifiApEnabled(WifiConfiguration, boolean)}
- * @param wifiConfig SSID, security and channel details as
- * part of WifiConfiguration
- * @param enabled true to enable and false to disable
- */
- @Override
- public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
- enforceChangePermission();
- mWifiPermissionsUtil.enforceTetherChangePermission(mContext);
-
- mLog.info("setWifiApEnabled uid=% enable=%").c(Binder.getCallingUid()).c(enabled).flush();
-
- if (mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING)) {
- throw new SecurityException("DISALLOW_CONFIG_TETHERING is enabled for this user.");
- }
- // null wifiConfig is a meaningful input for CMD_SET_AP
- if (wifiConfig == null || isValid(wifiConfig)) {
- int mode = WifiManager.IFACE_IP_MODE_UNSPECIFIED;
- SoftApModeConfiguration softApConfig = new SoftApModeConfiguration(mode, wifiConfig);
- mWifiController.sendMessage(CMD_SET_AP, enabled ? 1 : 0, 0, softApConfig);
- } else {
- Slog.e(TAG, "Invalid WifiConfiguration");
- }
- }
-
- /**
* see {@link WifiManager#getWifiApState()}
* @return One of {@link WifiManager#WIFI_AP_STATE_DISABLED},
* {@link WifiManager#WIFI_AP_STATE_DISABLING},
@@ -1588,6 +1558,26 @@
}
/**
+ * Return the list of all matching Wifi configurations for this ScanResult.
+ *
+ * An empty list will be returned when no configurations are installed or if no configurations
+ * match the ScanResult.
+ *
+ * @param scanResult scanResult that represents the BSSID
+ * @return A list of {@link WifiConfiguration}
+ */
+ @Override
+ public List<WifiConfiguration> getAllMatchingWifiConfigs(ScanResult scanResult) {
+ enforceAccessPermission();
+ mLog.info("getMatchingPasspointConfigurations uid=%").c(Binder.getCallingUid()).flush();
+ if (!mContext.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_WIFI_PASSPOINT)) {
+ throw new UnsupportedOperationException("Passpoint not enabled");
+ }
+ return mWifiStateMachine.getAllMatchingWifiConfigs(scanResult, mWifiStateMachineChannel);
+ }
+
+ /**
* Returns list of OSU (Online Sign-Up) providers associated with the given Passpoint network.
*
* @param scanResult scanResult of the Passpoint AP
@@ -1888,16 +1878,11 @@
/**
* Set the country code
* @param countryCode ISO 3166 country code.
- * @param persist {@code true} if the setting should be remembered.
*
- * The persist behavior exists so that wifi can fall back to the last
- * persisted country code on a restart, when the locale information is
- * not available from telephony.
*/
@Override
- public void setCountryCode(String countryCode, boolean persist) {
- Slog.i(TAG, "WifiService trying to set country code to " + countryCode +
- " with persist set to " + persist);
+ public void setCountryCode(String countryCode) {
+ Slog.i(TAG, "WifiService trying to set country code to " + countryCode);
enforceConnectivityInternalPermission();
mLog.info("setCountryCode uid=%").c(Binder.getCallingUid()).flush();
final long token = Binder.clearCallingIdentity();
@@ -2383,6 +2368,7 @@
@Override
public void enableVerboseLogging(int verbose) {
enforceAccessPermission();
+ enforceNetworkSettingsPermission();
mLog.info("enableVerboseLogging uid=% verbose=%")
.c(Binder.getCallingUid())
.c(verbose).flush();
@@ -2674,4 +2660,33 @@
restoreNetworks(wifiConfigurations);
Slog.d(TAG, "Restored supplicant backup data");
}
+
+ /**
+ * Starts subscription provisioning with a provider
+ *
+ * @param provider {@link OsuProvider} the provider to provision with
+ * @param callback {@link IProvisoningCallback} the callback object to inform status
+ */
+ @Override
+ public void startSubscriptionProvisioning(OsuProvider provider,
+ IProvisioningCallback callback) {
+ if (provider == null) {
+ throw new IllegalArgumentException("Provider must not be null");
+ }
+ if (callback == null) {
+ throw new IllegalArgumentException("Callback must not be null");
+ }
+ enforceNetworkSettingsPermission();
+ if (!mContext.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_WIFI_PASSPOINT)) {
+ throw new UnsupportedOperationException("Passpoint not enabled");
+ }
+ final int uid = Binder.getCallingUid();
+ mLog.trace("startSubscriptionProvisioning uid=%").c(uid).flush();
+ if (mWifiStateMachine.syncStartSubscriptionProvisioning(uid, provider,
+ callback, mWifiStateMachineChannel)) {
+ mLog.trace("Subscription provisioning started with %")
+ .c(provider.toString()).flush();
+ }
+ }
}
diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java
index ff3aea9..e386654 100644
--- a/service/java/com/android/server/wifi/WifiStateMachine.java
+++ b/service/java/com/android/server/wifi/WifiStateMachine.java
@@ -78,6 +78,7 @@
import android.net.wifi.WpsInfo;
import android.net.wifi.WpsResult;
import android.net.wifi.WpsResult.Status;
+import android.net.wifi.hotspot2.IProvisioningCallback;
import android.net.wifi.hotspot2.OsuProvider;
import android.net.wifi.hotspot2.PasspointConfiguration;
import android.net.wifi.p2p.IWifiP2pManager;
@@ -181,6 +182,7 @@
private static final String EXTRA_OSU_ICON_QUERY_BSSID = "BSSID";
private static final String EXTRA_OSU_ICON_QUERY_FILENAME = "FILENAME";
+ private static final String EXTRA_OSU_PROVIDER = "OsuProvider";
private boolean mVerboseLoggingEnabled = false;
@@ -250,8 +252,9 @@
private String mLastBssid;
private int mLastNetworkId; // The network Id we successfully joined
private boolean mIsLinkDebouncing = false;
- private final StateMachineDeathRecipient mDeathRecipient =
- new StateMachineDeathRecipient(this, CMD_CLIENT_INTERFACE_BINDER_DEATH);
+ private final WifiNative.WificondDeathEventHandler mWificondDeathRecipient = () -> {
+ sendMessage(CMD_WIFICOND_BINDER_DEATH);
+ };
private final WifiNative.VendorHalDeathEventHandler mVendorHalDeathRecipient = () -> {
sendMessage(CMD_VENDOR_HAL_HWBINDER_DEATH);
};
@@ -701,6 +704,9 @@
/* Enable/Disable AutoJoin when associated */
static final int CMD_ENABLE_AUTOJOIN_WHEN_ASSOCIATED = BASE + 167;
+ /* Get all matching Passpoint configurations */
+ static final int CMD_GET_ALL_MATCHING_CONFIGS = BASE + 168;
+
/**
* Used to handle messages bounced between WifiStateMachine and IpClient.
*/
@@ -725,8 +731,8 @@
/* used to indicate that the foreground user was switched */
static final int CMD_USER_STOP = BASE + 207;
- /* Signals that IClientInterface instance underpinning our state is dead. */
- private static final int CMD_CLIENT_INTERFACE_BINDER_DEATH = BASE + 250;
+ /* Signals that wificond is dead. */
+ private static final int CMD_WIFICOND_BINDER_DEATH = BASE + 250;
/* Signals that the Vendor HAL instance underpinning our state is dead. */
private static final int CMD_VENDOR_HAL_HWBINDER_DEATH = BASE + 251;
@@ -737,6 +743,9 @@
/* Used to set the tx power limit for SAR during the start of a phone call. */
private static final int CMD_SELECT_TX_POWER_SCENARIO = BASE + 253;
+ // Start subscription provisioning with a given provider
+ private static final int CMD_START_SUBSCRIPTION_PROVISIONING = BASE + 254;
+
// For message logging.
private static final Class[] sMessageClasses = {
AsyncChannel.class, WifiStateMachine.class, DhcpClient.class };
@@ -1243,6 +1252,7 @@
mWifiNative.enableVerboseLogging(verbose);
mWifiConfigManager.enableVerboseLogging(verbose);
mSupplicantStateTracker.enableVerboseLogging(verbose);
+ mPasspointManager.enableVerboseLogging(verbose);
}
private static final String SYSTEM_PROPERTY_LOG_CONTROL_WIFIHAL = "log.tag.WifiHAL";
@@ -1337,7 +1347,7 @@
return false;
}
if (!mWifiConfigManager.enableNetwork(netId, true, uid)
- || !mWifiConfigManager.checkAndUpdateLastConnectUid(netId, uid)) {
+ || !mWifiConfigManager.updateLastConnectUid(netId, uid)) {
logi("connectToUserSelectNetwork Allowing uid " + uid
+ " with insufficient permissions to connect=" + netId);
} else {
@@ -1463,9 +1473,8 @@
WifiLinkLayerStats getWifiLinkLayerStats() {
WifiLinkLayerStats stats = null;
if (mWifiLinkLayerStatsSupported > 0) {
- String name = "wlan0";
- stats = mWifiNative.getWifiLinkLayerStats(name);
- if (name != null && stats == null && mWifiLinkLayerStatsSupported > 0) {
+ stats = mWifiNative.getWifiLinkLayerStats();
+ if (stats == null && mWifiLinkLayerStatsSupported > 0) {
mWifiLinkLayerStatsSupported -= 1;
} else if (stats != null) {
lastLinkLayerStatsUpdate = mClock.getWallClockMillis();
@@ -1771,9 +1780,7 @@
uid) == PackageManager.PERMISSION_GRANTED) {
result.setMacAddress(mWifiInfo.getMacAddress());
}
- final WifiConfiguration currentWifiConfiguration = getCurrentWifiConfiguration();
- if (mWifiPermissionsUtil.canAccessFullConnectionInfo(
- currentWifiConfiguration,
+ if (mWifiPermissionsUtil.canAccessScanResults(
callingPackage,
uid,
Build.VERSION_CODES.O)) {
@@ -1940,6 +1947,15 @@
return config;
}
+ List<WifiConfiguration> getAllMatchingWifiConfigs(ScanResult scanResult,
+ AsyncChannel channel) {
+ Message resultMsg = channel.sendMessageSynchronously(CMD_GET_ALL_MATCHING_CONFIGS,
+ scanResult);
+ List<WifiConfiguration> configs = (List<WifiConfiguration>) resultMsg.obj;
+ resultMsg.recycle();
+ return configs;
+ }
+
/**
* Retrieve a list of {@link OsuProvider} associated with the given AP synchronously.
*
@@ -2001,6 +2017,25 @@
}
/**
+ * Start subscription provisioning synchronously
+ *
+ * @param provider {@link OsuProvider} the provider to provision with
+ * @param callback {@link IProvisioningCallback} callback for provisioning status
+ * @return boolean true indicates provisioning was started, false otherwise
+ */
+ public boolean syncStartSubscriptionProvisioning(int callingUid, OsuProvider provider,
+ IProvisioningCallback callback, AsyncChannel channel) {
+ Message msg = Message.obtain();
+ msg.what = CMD_START_SUBSCRIPTION_PROVISIONING;
+ msg.arg1 = callingUid;
+ msg.obj = callback;
+ msg.getData().putParcelable(EXTRA_OSU_PROVIDER, provider);
+ Message resultMsg = channel.sendMessageSynchronously(msg);
+ boolean result = resultMsg.arg1 != 0;
+ resultMsg.recycle();
+ return result;
+ }
+ /**
* Get connection statistics synchronously
*
* @param channel
@@ -2916,23 +2951,6 @@
mWifiApState.set(wifiApState);
if (mVerboseLoggingEnabled) log("setWifiApState: " + syncGetWifiApStateByName());
-
- final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
- intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiApState);
- intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousWifiApState);
- if (wifiApState == WifiManager.WIFI_AP_STATE_FAILED) {
- //only set reason number when softAP start failed
- intent.putExtra(WifiManager.EXTRA_WIFI_AP_FAILURE_REASON, reason);
- }
-
- if (ifaceName == null) {
- loge("Updating wifiApState with a null iface name");
- }
- intent.putExtra(WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME, ifaceName);
- intent.putExtra(WifiManager.EXTRA_WIFI_AP_MODE, mode);
-
- mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
private void setScanResults() {
@@ -3903,6 +3921,8 @@
break;
case CMD_INITIALIZE:
ok = mWifiNative.initializeVendorHal(mVendorHalDeathRecipient);
+ mPasspointManager.initializeProvisioner(
+ mWifiInjector.getWifiServiceHandlerThread().getLooper());
replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
break;
case CMD_BOOT_COMPLETED:
@@ -4035,6 +4055,9 @@
case CMD_GET_MATCHING_OSU_PROVIDERS:
replyToMessage(message, message.what, new ArrayList<OsuProvider>());
break;
+ case CMD_START_SUBSCRIPTION_PROVISIONING:
+ replyToMessage(message, message.what, 0);
+ break;
case CMD_IP_CONFIGURATION_SUCCESSFUL:
case CMD_IP_CONFIGURATION_LOST:
case CMD_IP_REACHABILITY_LOST:
@@ -4116,7 +4139,7 @@
mWifiNative.stopFilteringMulticastV4Packets();
}
break;
- case CMD_CLIENT_INTERFACE_BINDER_DEATH:
+ case CMD_WIFICOND_BINDER_DEATH:
Log.e(TAG, "wificond died unexpectedly. Triggering recovery");
mWifiMetrics.incrementNumWificondCrashes();
mWifiDiagnostics.captureBugReportData(
@@ -4133,6 +4156,9 @@
mWifiDiagnostics.reportConnectionEvent(
(Long) message.obj, BaseWifiDiagnostics.CONNECTION_EVENT_FAILED);
break;
+ case CMD_GET_ALL_MATCHING_CONFIGS:
+ replyToMessage(message, message.what, new ArrayList<WifiConfiguration>());
+ break;
case 0:
// We want to notice any empty messages (with what == 0) that might crop up.
// For example, we may have recycled a message sent to multiple handlers.
@@ -4152,7 +4178,7 @@
// Tearing down the client interfaces below is going to stop our supplicant.
mWifiMonitor.stopAllMonitoring();
- mDeathRecipient.unlinkToDeath();
+ mWifiNative.deregisterWificondDeathHandler();
mWifiNative.tearDown();
}
@@ -4168,14 +4194,14 @@
switch (message.what) {
case CMD_START_SUPPLICANT:
Pair<Integer, IClientInterface> statusAndInterface =
- mWifiNative.setupForClientMode();
+ mWifiNative.setupForClientMode(mInterfaceName);
if (statusAndInterface.first == WifiNative.SETUP_SUCCESS) {
mClientInterface = statusAndInterface.second;
} else {
incrementMetricsForSetupFailure(statusAndInterface.first);
}
if (mClientInterface == null
- || !mDeathRecipient.linkToDeath(mClientInterface.asBinder())) {
+ || !mWifiNative.registerWificondDeathHandler(mWificondDeathRecipient)) {
setWifiState(WifiManager.WIFI_STATE_UNKNOWN);
cleanup();
break;
@@ -5160,6 +5186,14 @@
replyToMessage(message, message.what,
mPasspointManager.getMatchingOsuProviders((ScanResult) message.obj));
break;
+ case CMD_START_SUBSCRIPTION_PROVISIONING:
+ IProvisioningCallback callback = (IProvisioningCallback) message.obj;
+ OsuProvider provider =
+ (OsuProvider) message.getData().getParcelable(EXTRA_OSU_PROVIDER);
+ int res = mPasspointManager.startSubscriptionProvisioning(
+ message.arg1, provider, callback) ? 1 : 0;
+ replyToMessage(message, message.what, res);
+ break;
case CMD_RECONNECT:
WorkSource workSource = (WorkSource) message.obj;
mWifiConnectivityManager.forceConnectivityScan(workSource);
@@ -5330,8 +5364,10 @@
}
break;
case WifiManager.START_WPS:
+ mWifiMetrics.incrementWpsAttemptCount();
WpsInfo wpsInfo = (WpsInfo) message.obj;
if (wpsInfo == null) {
+ mWifiMetrics.incrementWpsStartFailureCount();
loge("Cannot start WPS with null WpsInfo object");
replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.ERROR);
break;
@@ -5377,6 +5413,7 @@
replyToMessage(message, WifiManager.START_WPS_SUCCEEDED, wpsResult);
transitionTo(mWpsRunningState);
} else {
+ mWifiMetrics.incrementWpsStartFailureCount();
loge("Failed to start WPS with config " + wpsInfo.toString());
replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.ERROR);
}
@@ -5496,6 +5533,10 @@
case CMD_ENABLE_P2P:
p2pSendMessage(WifiStateMachine.CMD_ENABLE_P2P);
break;
+ case CMD_GET_ALL_MATCHING_CONFIGS:
+ replyToMessage(message, message.what,
+ mPasspointManager.getAllMatchingWifiConfigs((ScanResult) message.obj));
+ break;
default:
return NOT_HANDLED;
}
@@ -6798,8 +6839,10 @@
int netId = loadResult.second;
if (success) {
message.arg1 = netId;
+ mWifiMetrics.incrementWpsSuccessCount();
replyToMessage(mSourceMessage, WifiManager.WPS_COMPLETED);
} else {
+ mWifiMetrics.incrementWpsSupplicantFailureCount();
replyToMessage(mSourceMessage, WifiManager.WPS_FAILED,
WifiManager.ERROR);
}
@@ -6809,6 +6852,7 @@
transitionTo(mDisconnectedState);
break;
case WifiMonitor.WPS_OVERLAP_EVENT:
+ mWifiMetrics.incrementWpsOverlapFailureCount();
replyToMessage(mSourceMessage, WifiManager.WPS_FAILED,
WifiManager.WPS_OVERLAP_ERROR);
mSourceMessage.recycle();
@@ -6818,6 +6862,7 @@
case WifiMonitor.WPS_FAIL_EVENT:
// Arg1 has the reason for the failure
if ((message.arg1 != WifiManager.ERROR) || (message.arg2 != 0)) {
+ mWifiMetrics.incrementWpsOtherConnectionFailureCount();
replyToMessage(mSourceMessage, WifiManager.WPS_FAILED, message.arg1);
mSourceMessage.recycle();
mSourceMessage = null;
@@ -6829,6 +6874,7 @@
}
break;
case WifiMonitor.WPS_TIMEOUT_EVENT:
+ mWifiMetrics.incrementWpsTimeoutFailureCount();
replyToMessage(mSourceMessage, WifiManager.WPS_FAILED,
WifiManager.WPS_TIMED_OUT);
mSourceMessage.recycle();
@@ -6839,6 +6885,7 @@
replyToMessage(message, WifiManager.WPS_FAILED, WifiManager.IN_PROGRESS);
break;
case WifiManager.CANCEL_WPS:
+ mWifiMetrics.incrementWpsCancellationCount();
if (mWifiNative.cancelWps()) {
replyToMessage(message, WifiManager.CANCEL_WPS_SUCCEDED);
} else {
@@ -6958,7 +7005,8 @@
mMode = config.getTargetMode();
IApInterface apInterface = null;
- Pair<Integer, IApInterface> statusAndInterface = mWifiNative.setupForSoftApMode();
+ Pair<Integer, IApInterface> statusAndInterface =
+ mWifiNative.setupForSoftApMode(mInterfaceName);
if (statusAndInterface.first == WifiNative.SETUP_SUCCESS) {
apInterface = statusAndInterface.second;
} else {
@@ -6967,10 +7015,7 @@
if (apInterface == null) {
setWifiApState(WIFI_AP_STATE_FAILED,
WifiManager.SAP_START_FAILURE_GENERAL, null, mMode);
- /**
- * Transition to InitialState to reset the
- * driver/HAL back to the initial state.
- */
+ // Transition to InitialState to reset the driver/HAL back to the initial state.
transitionTo(mInitialState);
return;
}
@@ -6978,16 +7023,20 @@
try {
mIfaceName = apInterface.getInterfaceName();
} catch (RemoteException e) {
- // Failed to get the interface name. The name will not be available for
- // the enabled broadcast, but since we had an error getting the name, we most likely
- // won't be able to fully start softap mode.
+ // Failed to get the interface name. This is not a good sign and we should report
+ // a failure and switch back to the initial state to reset the driver and HAL.
+ setWifiApState(WIFI_AP_STATE_FAILED,
+ WifiManager.SAP_START_FAILURE_GENERAL, null, mMode);
+ transitionTo(mInitialState);
+ return;
}
checkAndSetConnectivityInstance();
mSoftApManager = mWifiInjector.makeSoftApManager(mNwService,
new SoftApListener(),
apInterface,
- config.getWifiConfiguration());
+ mIfaceName,
+ config);
mSoftApManager.start();
mWifiStateTracker.updateState(WifiStateTracker.SOFT_AP);
}
diff --git a/service/java/com/android/server/wifi/WifiStateMachinePrime.java b/service/java/com/android/server/wifi/WifiStateMachinePrime.java
index 2006884..c49b645 100644
--- a/service/java/com/android/server/wifi/WifiStateMachinePrime.java
+++ b/service/java/com/android/server/wifi/WifiStateMachinePrime.java
@@ -16,6 +16,7 @@
package com.android.server.wifi;
+import android.annotation.NonNull;
import android.net.wifi.IApInterface;
import android.net.wifi.IWificond;
import android.net.wifi.WifiConfiguration;
@@ -50,7 +51,7 @@
private IWificond mWificond;
- private Queue<WifiConfiguration> mApConfigQueue = new ConcurrentLinkedQueue<>();
+ private Queue<SoftApModeConfiguration> mApConfigQueue = new ConcurrentLinkedQueue<>();
/* The base for wifi message types */
static final int BASE = Protocol.BASE_WIFI;
@@ -106,17 +107,13 @@
/**
* Method to enable soft ap for wifi hotspot.
*
- * The WifiConfiguration is generally going to be null to indicate that the
- * currently saved config in WifiApConfigManager should be used. When the config is
- * not null, it will be saved in the WifiApConfigManager. This save is performed in the
- * constructor of SoftApManager.
+ * The supplied SoftApModeConfiguration includes the target softap WifiConfiguration (or null if
+ * the persisted config is to be used) and the target operating mode (ex,
+ * {@link WifiManager.IFACE_IP_MODE_TETHERED} {@link WifiManager.IFACE_IP_MODE_LOCAL_ONLY}).
*
- * @param wifiConfig WifiConfiguration for the hostapd softap
+ * @param wifiConfig SoftApModeConfiguration for the hostapd softap
*/
- public void enterSoftAPMode(WifiConfiguration wifiConfig) {
- if (wifiConfig == null) {
- wifiConfig = new WifiConfiguration();
- }
+ public void enterSoftAPMode(@NonNull SoftApModeConfiguration wifiConfig) {
mApConfigQueue.offer(wifiConfig);
changeMode(ModeStateMachine.CMD_START_SOFT_AP_MODE);
}
@@ -270,6 +267,7 @@
class SoftAPModeState extends State {
IApInterface mApInterface = null;
+ String mIfaceName = null;
@Override
public void enter() {
@@ -281,22 +279,18 @@
// Continue with setup since we are changing modes
mApInterface = null;
- mWificond = mWifiInjector.makeWificond();
- if (mWificond == null) {
- Log.e(TAG, "Failed to get reference to wificond");
- writeApConfigDueToStartFailure();
- mModeStateMachine.sendMessage(CMD_START_AP_FAILURE);
- return;
- }
try {
- mApInterface = mWificond.createApInterface();
- } catch (RemoteException e1) { }
-
- if (mApInterface == null) {
- Log.e(TAG, "Could not get IApInterface instance from wificond");
- writeApConfigDueToStartFailure();
- mModeStateMachine.sendMessage(CMD_START_AP_FAILURE);
+ mWificond = mWifiInjector.makeWificond();
+ mApInterface = mWificond.createApInterface(
+ mWifiInjector.getWifiNative().getInterfaceName());
+ mIfaceName = mApInterface.getInterfaceName();
+ } catch (RemoteException e) {
+ initializationFailed(
+ "Could not get IApInterface instance or its name from wificond");
+ return;
+ } catch (NullPointerException e) {
+ initializationFailed("wificond failure when initializing softap mode");
return;
}
mModeStateMachine.transitionTo(mSoftAPModeActiveState);
@@ -316,6 +310,8 @@
// not in active state, nothing to stop.
break;
case CMD_START_AP_FAILURE:
+ // remove the saved config for the start attempt
+ mApConfigQueue.poll();
Log.e(TAG, "Failed to start SoftApMode. Wait for next mode command.");
break;
case CMD_AP_STOPPED:
@@ -336,12 +332,13 @@
return mApInterface;
}
- private void writeApConfigDueToStartFailure() {
- WifiConfiguration config = mApConfigQueue.poll();
- if (config != null && config.SSID != null) {
- // Save valid configs for future calls.
- mWifiInjector.getWifiApConfigStore().setApConfiguration(config);
- }
+ protected String getInterfaceName() {
+ return mIfaceName;
+ }
+
+ private void initializationFailed(String message) {
+ Log.e(TAG, message);
+ mModeStateMachine.sendMessage(CMD_START_AP_FAILURE);
}
}
@@ -409,16 +406,17 @@
@Override
public void enter() {
Log.d(TAG, "Entering SoftApModeActiveState");
- WifiConfiguration config = mApConfigQueue.poll();
+ SoftApModeConfiguration softApModeConfig = mApConfigQueue.poll();
+ WifiConfiguration config = softApModeConfig.getWifiConfiguration();
+ // TODO (b/67601382): add checks for valid softap configs
if (config != null && config.SSID != null) {
Log.d(TAG, "Passing config to SoftApManager! " + config);
} else {
config = null;
}
-
this.mActiveModeManager = mWifiInjector.makeSoftApManager(mNMService,
new SoftApListener(), ((SoftAPModeState) mSoftAPModeState).getInterface(),
- config);
+ ((SoftAPModeState) mSoftAPModeState).getInterfaceName(), softApModeConfig);
mActiveModeManager.start();
}
diff --git a/service/java/com/android/server/wifi/WifiVendorHal.java b/service/java/com/android/server/wifi/WifiVendorHal.java
index 12674aa..d552e7d 100644
--- a/service/java/com/android/server/wifi/WifiVendorHal.java
+++ b/service/java/com/android/server/wifi/WifiVendorHal.java
@@ -67,16 +67,22 @@
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
+import android.text.TextUtils;
+import android.util.Log;
import android.util.MutableBoolean;
import android.util.MutableInt;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.server.connectivity.KeepalivePacketData;
+import com.android.server.wifi.HalDeviceManager.InterfaceDestroyedListener;
import com.android.server.wifi.util.BitMask;
import com.android.server.wifi.util.NativeUtil;
+import libcore.util.NonNull;
+
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.Set;
/**
@@ -138,7 +144,7 @@
}
/**
- * Logs if the argument is false.
+ * Logs the argument along with the method name.
*
* Always returns its argument.
*/
@@ -158,6 +164,26 @@
}
/**
+ * Logs the argument along with the method name.
+ *
+ * Always returns its argument.
+ */
+ private String stringResult(String result) {
+ if (mVerboseLog == sNoLog) return result;
+ // Currently only seen if verbose logging is on
+
+ Thread cur = Thread.currentThread();
+ StackTraceElement[] trace = cur.getStackTrace();
+
+ mVerboseLog.err("% returns %")
+ .c(niceMethodName(trace, 3))
+ .c(result)
+ .flush();
+
+ return result;
+ }
+
+ /**
* Logs at method entry
*
* @param format string with % placeholders
@@ -200,9 +226,9 @@
// Vendor HAL HIDL interface objects.
private IWifiChip mIWifiChip;
- private IWifiStaIface mIWifiStaIface;
- private IWifiApIface mIWifiApIface;
private IWifiRttController mIWifiRttController;
+ private HashMap<String, IWifiStaIface> mIWifiStaIfaces = new HashMap<>();
+ private HashMap<String, IWifiApIface> mIWifiApIfaces = new HashMap<>();
private final HalDeviceManager mHalDeviceManager;
private final HalDeviceManagerStatusListener mHalDeviceManagerStatusCallbacks;
private final IWifiStaIfaceEventCallback mIWifiStaIfaceEventCallback;
@@ -248,7 +274,8 @@
public boolean initialize(WifiNative.VendorHalDeathEventHandler handler) {
synchronized (sLock) {
mHalDeviceManager.initialize();
- mHalDeviceManager.registerStatusListener(mHalDeviceManagerStatusCallbacks, mLooper);
+ mHalDeviceManager.registerStatusListener(mHalDeviceManagerStatusCallbacks,
+ mHalEventHandler);
mDeathEventHandler = handler;
return true;
}
@@ -269,7 +296,16 @@
* @return true for success
*/
public boolean startVendorHalAp() {
- return startVendorHal(AP_MODE);
+ synchronized (sLock) {
+ if (!startVendorHal()) {
+ return false;
+ }
+ if (TextUtils.isEmpty(createApIface(null))) {
+ stopVendorHal();
+ return false;
+ }
+ return true;
+ }
}
/**
@@ -278,85 +314,182 @@
* @return true for success
*/
public boolean startVendorHalSta() {
- return startVendorHal(STA_MODE);
+ synchronized (sLock) {
+ if (!startVendorHal()) {
+ return false;
+ }
+ if (TextUtils.isEmpty(createStaIface(null))) {
+ stopVendorHal();
+ return false;
+ }
+ return true;
+ }
}
- public static final boolean STA_MODE = true;
- public static final boolean AP_MODE = false;
-
/**
- * Bring up the HIDL Vendor HAL and configure for STA mode or AP mode.
- *
- * @param isStaMode true to start HAL in STA mode, false to start in AP mode.
+ * Bring up the HIDL Vendor HAL.
+ * @return true on success, false otherwise.
*/
- public boolean startVendorHal(boolean isStaMode) {
+ public boolean startVendorHal() {
synchronized (sLock) {
- if (mIWifiStaIface != null) return boolResult(false);
- if (mIWifiApIface != null) return boolResult(false);
if (!mHalDeviceManager.start()) {
- return startFailedTo("start the vendor HAL");
- }
- IWifiIface iface;
- if (isStaMode) {
- mIWifiStaIface = mHalDeviceManager.createStaIface(null, null);
- if (mIWifiStaIface == null) {
- return startFailedTo("create STA Iface");
- }
- iface = (IWifiIface) mIWifiStaIface;
- if (!registerStaIfaceCallback()) {
- return startFailedTo("register sta iface callback");
- }
- mIWifiRttController = mHalDeviceManager.createRttController(iface);
- if (mIWifiRttController == null) {
- return startFailedTo("create RTT controller");
- }
- if (!registerRttEventCallback()) {
- return startFailedTo("register RTT iface callback");
- }
- enableLinkLayerStats();
- } else {
- mIWifiApIface = mHalDeviceManager.createApIface(null, null);
- if (mIWifiApIface == null) {
- return startFailedTo("create AP Iface");
- }
- iface = (IWifiIface) mIWifiApIface;
- }
- mIWifiChip = mHalDeviceManager.getChip(iface);
- if (mIWifiChip == null) {
- return startFailedTo("get the chip created for the Iface");
- }
- if (!registerChipCallback()) {
- return startFailedTo("register chip callback");
+ mLog.err("Failed to start vendor HAL");
+ return false;
}
mLog.i("Vendor Hal started successfully");
return true;
}
}
+ /** Helper method to lookup the corresponding STA iface object using iface name. */
+ private IWifiStaIface getStaIface(@NonNull String ifaceName) {
+ synchronized (sLock) {
+ return mIWifiStaIfaces.get(ifaceName);
+ }
+ }
+
/**
- * Logs a message and cleans up after a failing start attempt
+ * Create a STA iface using {@link HalDeviceManager}.
*
- * The lock should be held.
- * @param message describes what was being attempted
- * @return false
+ * @param destroyedListener Listener to be invoked when the interface is destroyed.
+ * @return iface name on success, null otherwise.
*/
- private boolean startFailedTo(String message) {
- mVerboseLog.err("Failed to %. Vendor Hal start failed").c(message).flush();
- mHalDeviceManager.stop();
- clearState();
- return false;
+ public String createStaIface(InterfaceDestroyedListener destroyedListener) {
+ synchronized (sLock) {
+ IWifiStaIface iface;
+ iface = mHalDeviceManager.createStaIface(destroyedListener, null);
+ if (iface == null) {
+ mLog.err("Failed to create STA iface");
+ return stringResult(null);
+ }
+ String ifaceName = mHalDeviceManager.getName((IWifiIface) iface);
+ if (TextUtils.isEmpty(ifaceName)) {
+ mLog.err("Failed to get iface name");
+ return stringResult(null);
+ }
+ if (!registerStaIfaceCallback(iface)) {
+ mLog.err("Failed to register STA iface callback");
+ return stringResult(null);
+ }
+ mIWifiRttController = mHalDeviceManager.createRttController();
+ if (mIWifiRttController == null) {
+ mLog.err("Failed to create RTT controller");
+ return stringResult(null);
+ }
+ if (!registerRttEventCallback()) {
+ mLog.err("Failed to register RTT controller callback");
+ return stringResult(null);
+ }
+ if (!retrieveWifiChip((IWifiIface) iface)) {
+ mLog.err("Failed to get wifi chip");
+ return stringResult(null);
+ }
+ enableLinkLayerStats(iface);
+ mIWifiStaIfaces.put(ifaceName, iface);
+ return ifaceName;
+ }
+ }
+
+ /**
+ * Remove a STA iface using {@link HalDeviceManager}.
+ *
+ * @param ifaceName Name of the interface being removed.
+ * @return true on success, false otherwise.
+ */
+ public boolean removeStaIface(@NonNull String ifaceName) {
+ synchronized (sLock) {
+ IWifiStaIface iface = getStaIface(ifaceName);
+ if (iface == null) return boolResult(false);
+
+ if (!mHalDeviceManager.removeIface((IWifiIface) iface)) {
+ mLog.err("Failed to remove STA iface");
+ return boolResult(false);
+ }
+ mIWifiStaIfaces.remove(ifaceName);
+ return true;
+ }
+ }
+
+ /** Helper method to lookup the corresponding AP iface object using iface name. */
+ private IWifiApIface getApIface(@NonNull String ifaceName) {
+ synchronized (sLock) {
+ return mIWifiApIfaces.get(ifaceName);
+ }
+ }
+
+ /**
+ * Create a AP iface using {@link HalDeviceManager}.
+ *
+ * @param destroyedListener Listener to be invoked when the interface is destroyed.
+ * @return iface name on success, null otherwise.
+ */
+ public String createApIface(InterfaceDestroyedListener destroyedListener) {
+ synchronized (sLock) {
+ IWifiApIface iface;
+ iface = mHalDeviceManager.createApIface(destroyedListener, null);
+ if (iface == null) {
+ mLog.err("Failed to create AP iface");
+ return stringResult(null);
+ }
+ String ifaceName = mHalDeviceManager.getName((IWifiIface) iface);
+ if (TextUtils.isEmpty(ifaceName)) {
+ mLog.err("Failed to get iface name");
+ return stringResult(null);
+ }
+ if (!retrieveWifiChip((IWifiIface) iface)) {
+ mLog.err("Failed to get wifi chip");
+ return stringResult(null);
+ }
+ mIWifiApIfaces.put(ifaceName, iface);
+ return ifaceName;
+ }
+ }
+
+ /**
+ * Remove an AP iface using {@link HalDeviceManager}.
+ *
+ * @param ifaceName Name of the interface being removed.
+ * @return true on success, false otherwise.
+ */
+ public boolean removeApIface(@NonNull String ifaceName) {
+ synchronized (sLock) {
+ IWifiApIface iface = getApIface(ifaceName);
+ if (iface == null) return boolResult(false);
+
+ if (!mHalDeviceManager.removeIface((IWifiIface) iface)) {
+ mLog.err("Failed to remove AP iface");
+ return boolResult(false);
+ }
+ mIWifiApIfaces.remove(ifaceName);
+ return true;
+ }
+ }
+
+ private boolean retrieveWifiChip(IWifiIface iface) {
+ synchronized (sLock) {
+ mIWifiChip = mHalDeviceManager.getChip(iface);
+ if (mIWifiChip == null) {
+ mLog.err("Failed to get the chip created for the Iface");
+ return false;
+ }
+ if (!registerChipCallback()) {
+ mLog.err("Failed to register chip callback");
+ return false;
+ }
+ return true;
+ }
}
/**
* Registers the sta iface callback.
*/
- private boolean registerStaIfaceCallback() {
+ private boolean registerStaIfaceCallback(IWifiStaIface iface) {
synchronized (sLock) {
- if (mIWifiStaIface == null) return boolResult(false);
+ if (iface == null) return boolResult(false);
if (mIWifiStaIfaceEventCallback == null) return boolResult(false);
try {
WifiStatus status =
- mIWifiStaIface.registerEventCallback(mIWifiStaIfaceEventCallback);
+ iface.registerEventCallback(mIWifiStaIfaceEventCallback);
return ok(status);
} catch (RemoteException e) {
handleRemoteException(e);
@@ -388,6 +521,7 @@
private boolean registerRttEventCallback() {
synchronized (sLock) {
if (mIWifiRttController == null) return boolResult(false);
+ if (mRttEventCallback == null) return boolResult(false);
try {
WifiStatus status = mIWifiRttController.registerEventCallback(mRttEventCallback);
return ok(status);
@@ -416,37 +550,39 @@
*/
private void clearState() {
mIWifiChip = null;
- mIWifiStaIface = null;
- mIWifiApIface = null;
+ mIWifiStaIfaces.clear();
+ mIWifiApIfaces.clear();
mIWifiRttController = null;
mDriverDescription = null;
mFirmwareDescription = null;
- mChannelsForBandSupport = null;
}
/**
- * Tests whether the HAL is running or not
+ * Tests whether the HAL is started and atleast one iface is up.
*/
public boolean isHalStarted() {
// For external use only. Methods in this class should test for null directly.
synchronized (sLock) {
- return (mIWifiStaIface != null || mIWifiApIface != null);
+ return (!mIWifiStaIfaces.isEmpty() || !mIWifiApIfaces.isEmpty());
}
}
/**
* Gets the scan capabilities
*
+ * @param ifaceName Name of the interface.
* @param capabilities object to be filled in
* @return true for success, false for failure
*/
- public boolean getBgScanCapabilities(WifiNative.ScanCapabilities capabilities) {
+ public boolean getBgScanCapabilities(
+ @NonNull String ifaceName, WifiNative.ScanCapabilities capabilities) {
synchronized (sLock) {
- if (mIWifiStaIface == null) return boolResult(false);
+ IWifiStaIface iface = getStaIface(ifaceName);
+ if (iface == null) return boolResult(false);
try {
MutableBoolean ans = new MutableBoolean(false);
WifiNative.ScanCapabilities out = capabilities;
- mIWifiStaIface.getBackgroundScanCapabilities((status, cap) -> {
+ iface.getBackgroundScanCapabilities((status, cap) -> {
if (!ok(status)) return;
mVerboseLog.info("scan capabilities %").c(cap.toString()).flush();
out.max_scan_cache_size = cap.maxCacheSize;
@@ -581,24 +717,27 @@
*
* Any ongoing scan will be stopped first
*
+ * @param ifaceName Name of the interface.
* @param settings to control the scan
* @param eventHandler to call with the results
* @return true for success
*/
- public boolean startBgScan(WifiNative.ScanSettings settings,
+ public boolean startBgScan(@NonNull String ifaceName,
+ WifiNative.ScanSettings settings,
WifiNative.ScanEventHandler eventHandler) {
WifiStatus status;
if (eventHandler == null) return boolResult(false);
synchronized (sLock) {
- if (mIWifiStaIface == null) return boolResult(false);
+ IWifiStaIface iface = getStaIface(ifaceName);
+ if (iface == null) return boolResult(false);
try {
if (mScan != null && !mScan.paused) {
- ok(mIWifiStaIface.stopBackgroundScan(mScan.cmdId));
+ ok(iface.stopBackgroundScan(mScan.cmdId));
mScan = null;
}
mLastScanCmdId = (mLastScanCmdId % 9) + 1; // cycle through non-zero single digits
CurrentBackgroundScan scan = new CurrentBackgroundScan(mLastScanCmdId, settings);
- status = mIWifiStaIface.startBackgroundScan(scan.cmdId, scan.param);
+ status = iface.startBackgroundScan(scan.cmdId, scan.param);
if (!ok(status)) return false;
scan.eventHandler = eventHandler;
mScan = scan;
@@ -613,14 +752,17 @@
/**
* Stops any ongoing backgound scan
+ *
+ * @param ifaceName Name of the interface.
*/
- public void stopBgScan() {
+ public void stopBgScan(@NonNull String ifaceName) {
WifiStatus status;
synchronized (sLock) {
- if (mIWifiStaIface == null) return;
+ IWifiStaIface iface = getStaIface(ifaceName);
+ if (iface == null) return;
try {
if (mScan != null) {
- ok(mIWifiStaIface.stopBackgroundScan(mScan.cmdId));
+ ok(iface.stopBackgroundScan(mScan.cmdId));
mScan = null;
}
} catch (RemoteException e) {
@@ -631,14 +773,17 @@
/**
* Pauses an ongoing backgound scan
+ *
+ * @param ifaceName Name of the interface.
*/
- public void pauseBgScan() {
+ public void pauseBgScan(@NonNull String ifaceName) {
WifiStatus status;
synchronized (sLock) {
try {
- if (mIWifiStaIface == null) return;
+ IWifiStaIface iface = getStaIface(ifaceName);
+ if (iface == null) return;
if (mScan != null && !mScan.paused) {
- status = mIWifiStaIface.stopBackgroundScan(mScan.cmdId);
+ status = iface.stopBackgroundScan(mScan.cmdId);
if (!ok(status)) return;
mScan.paused = true;
}
@@ -650,14 +795,17 @@
/**
* Restarts a paused background scan
+ *
+ * @param ifaceName Name of the interface.
*/
- public void restartBgScan() {
+ public void restartBgScan(@NonNull String ifaceName) {
WifiStatus status;
synchronized (sLock) {
- if (mIWifiStaIface == null) return;
+ IWifiStaIface iface = getStaIface(ifaceName);
+ if (iface == null) return;
try {
if (mScan != null && mScan.paused) {
- status = mIWifiStaIface.startBackgroundScan(mScan.cmdId, mScan.param);
+ status = iface.startBackgroundScan(mScan.cmdId, mScan.param);
if (!ok(status)) return;
mScan.paused = false;
}
@@ -671,10 +819,13 @@
* Gets the latest scan results received from the HIDL interface callback.
* TODO(b/35754840): This hop to fetch scan results after callback is unnecessary. Refactor
* WifiScanner to use the scan results from the callback.
+ *
+ * @param ifaceName Name of the interface.
*/
- public WifiScanner.ScanData[] getBgScanResults() {
+ public WifiScanner.ScanData[] getBgScanResults(@NonNull String ifaceName) {
synchronized (sLock) {
- if (mIWifiStaIface == null) return null;
+ IWifiStaIface iface = getStaIface(ifaceName);
+ if (iface == null) return null;
if (mScan == null) return null;
return mScan.latestScanResults;
}
@@ -685,17 +836,19 @@
*
* Note - we always enable link layer stats on a STA interface.
*
+ * @param ifaceName Name of the interface.
* @return the statistics, or null if unable to do so
*/
- public WifiLinkLayerStats getWifiLinkLayerStats() {
+ public WifiLinkLayerStats getWifiLinkLayerStats(@NonNull String ifaceName) {
class AnswerBox {
public StaLinkLayerStats value = null;
}
AnswerBox answer = new AnswerBox();
synchronized (sLock) {
try {
- if (mIWifiStaIface == null) return null;
- mIWifiStaIface.getLinkLayerStats((status, stats) -> {
+ IWifiStaIface iface = getStaIface(ifaceName);
+ if (iface == null) return null;
+ iface.getLinkLayerStats((status, stats) -> {
if (!ok(status)) return;
answer.value = stats;
});
@@ -762,12 +915,14 @@
* Enables the linkLayerStats in the Hal.
*
* This is called unconditionally whenever we create a STA interface.
+ *
+ * @param iface Iface object.
*/
- private void enableLinkLayerStats() {
+ private void enableLinkLayerStats(IWifiStaIface iface) {
synchronized (sLock) {
try {
WifiStatus status;
- status = mIWifiStaIface.enableLinkLayerStatsCollection(mLinkLayerStatsDebug);
+ status = iface.enableLinkLayerStatsCollection(mLinkLayerStatsDebug);
if (!ok(status)) {
mLog.e("unable to enable link layer stats collection");
}
@@ -876,9 +1031,10 @@
*
* The result may differ depending on the mode (STA or AP)
*
+ * @param ifaceName Name of the interface.
* @return bitmask defined by WifiManager.WIFI_FEATURE_*
*/
- public int getSupportedFeatureSet() {
+ public int getSupportedFeatureSet(@NonNull String ifaceName) {
int featureSet = 0;
if (!mHalDeviceManager.isStarted()) {
return featureSet; // TODO: can't get capabilities with Wi-Fi down
@@ -892,8 +1048,9 @@
feat.value = wifiFeatureMaskFromChipCapabilities(capabilities);
});
}
- if (mIWifiStaIface != null) {
- mIWifiStaIface.getCapabilities((status, capabilities) -> {
+ IWifiStaIface iface = getStaIface(ifaceName);
+ if (iface != null) {
+ iface.getCapabilities((status, capabilities) -> {
if (!ok(status)) return;
feat.value |= wifiFeatureMaskFromStaCapabilities(capabilities);
});
@@ -1432,16 +1589,18 @@
* An OUI {Organizationally Unique Identifier} is a 24-bit number that
* uniquely identifies a vendor or manufacturer.
*
+ * @param ifaceName Name of the interface.
* @param oui
* @return true for success
*/
- public boolean setScanningMacOui(byte[] oui) {
+ public boolean setScanningMacOui(@NonNull String ifaceName, byte[] oui) {
if (oui == null) return boolResult(false);
if (oui.length != 3) return boolResult(false);
synchronized (sLock) {
try {
- if (mIWifiStaIface == null) return boolResult(false);
- WifiStatus status = mIWifiStaIface.setScanningMacOui(oui);
+ IWifiStaIface iface = getStaIface(ifaceName);
+ if (iface == null) return boolResult(false);
+ WifiStatus status = iface.setScanningMacOui(oui);
if (!ok(status)) return false;
return true;
} catch (RemoteException e) {
@@ -1452,89 +1611,21 @@
}
/**
- * Query the list of valid frequencies for the provided band.
- * <p>
- * 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.
- * @return frequencies vector of valid frequencies (MHz), or null for error.
- * @throws IllegalArgumentException if band is not recognized.
- */
- public int[] getChannelsForBand(int band) {
- enter("%").c(band).flush();
- class AnswerBox {
- public int[] value = null;
- }
- synchronized (sLock) {
- try {
- AnswerBox box = new AnswerBox();
- int hb = makeWifiBandFromFrameworkBand(band);
- if (mIWifiStaIface != null) {
- mIWifiStaIface.getValidFrequenciesForBand(hb, (status, frequencies) -> {
- if (status.code == WifiStatusCode.ERROR_NOT_SUPPORTED) {
- mChannelsForBandSupport = false;
- }
- if (!ok(status)) return;
- mChannelsForBandSupport = true;
- box.value = intArrayFromArrayList(frequencies);
- });
- } else if (mIWifiApIface != null) {
- mIWifiApIface.getValidFrequenciesForBand(hb, (status, frequencies) -> {
- if (status.code == WifiStatusCode.ERROR_NOT_SUPPORTED) {
- mChannelsForBandSupport = false;
- }
- if (!ok(status)) return;
- mChannelsForBandSupport = true;
- box.value = intArrayFromArrayList(frequencies);
- });
- }
- return box.value;
- } catch (RemoteException e) {
- handleRemoteException(e);
- return null;
- }
- }
- }
-
- private int[] intArrayFromArrayList(ArrayList<Integer> in) {
- int[] ans = new int[in.size()];
- int i = 0;
- for (Integer e : in) ans[i++] = e;
- return ans;
- }
-
- /**
- * This holder is null until we know whether or not there is frequency-for-band support.
- * <p>
- * Set as a side-effect of getChannelsForBand.
- */
- @VisibleForTesting
- Boolean mChannelsForBandSupport = null;
-
- /**
- * Indicates whether getChannelsForBand is supported.
- *
- * @return true if it is.
- */
- public boolean isGetChannelsForBandSupported() {
- if (mChannelsForBandSupport != null) return mChannelsForBandSupport;
- getChannelsForBand(WifiBand.BAND_24GHZ);
- if (mChannelsForBandSupport != null) return mChannelsForBandSupport;
- return false;
- }
-
- /**
* Get the APF (Android Packet Filter) capabilities of the device
+ *
+ * @param ifaceName Name of the interface.
+ * @return APF capabilities object.
*/
- public ApfCapabilities getApfCapabilities() {
+ public ApfCapabilities getApfCapabilities(@NonNull String ifaceName) {
class AnswerBox {
public ApfCapabilities value = sNoApfCapabilities;
}
synchronized (sLock) {
try {
- if (mIWifiStaIface == null) return sNoApfCapabilities;
+ IWifiStaIface iface = getStaIface(ifaceName);
+ if (iface == null) return sNoApfCapabilities;
AnswerBox box = new AnswerBox();
- mIWifiStaIface.getApfPacketFilterCapabilities((status, capabilities) -> {
+ iface.getApfPacketFilterCapabilities((status, capabilities) -> {
if (!ok(status)) return;
box.value = new ApfCapabilities(
/* apfVersionSupported */ capabilities.version,
@@ -1554,10 +1645,11 @@
/**
* Installs an APF program on this iface, replacing any existing program.
*
+ * @param ifaceName Name of the interface.
* @param filter is the android packet filter program
* @return true for success
*/
- public boolean installPacketFilter(byte[] filter) {
+ public boolean installPacketFilter(@NonNull String ifaceName, byte[] filter) {
int cmdId = 0; // We only aspire to support one program at a time
if (filter == null) return boolResult(false);
// Copy the program before taking the lock.
@@ -1565,8 +1657,9 @@
enter("filter length %").c(filter.length).flush();
synchronized (sLock) {
try {
- if (mIWifiStaIface == null) return boolResult(false);
- WifiStatus status = mIWifiStaIface.installApfPacketFilter(cmdId, program);
+ IWifiStaIface iface = getStaIface(ifaceName);
+ if (iface == null) return boolResult(false);
+ WifiStatus status = iface.installApfPacketFilter(cmdId, program);
if (!ok(status)) return false;
return true;
} catch (RemoteException e) {
@@ -1579,10 +1672,11 @@
/**
* Set country code for this AP iface.
*
+ * @param ifaceName Name of the interface.
* @param countryCode - two-letter country code (as ISO 3166)
* @return true for success
*/
- public boolean setCountryCodeHal(String countryCode) {
+ public boolean setCountryCodeHal(@NonNull String ifaceName, String countryCode) {
if (countryCode == null) return boolResult(false);
if (countryCode.length() != 2) return boolResult(false);
byte[] code;
@@ -1593,8 +1687,9 @@
}
synchronized (sLock) {
try {
- if (mIWifiApIface == null) return boolResult(false);
- WifiStatus status = mIWifiApIface.setCountryCode(code);
+ IWifiApIface iface = getApIface(ifaceName);
+ if (iface == null) return boolResult(false);
+ WifiStatus status = iface.setCountryCode(code);
if (!ok(status)) return false;
return true;
} catch (RemoteException e) {
@@ -1880,13 +1975,15 @@
* <p>
* Once started, monitoring remains active until HAL is unloaded.
*
+ * @param ifaceName Name of the interface.
* @return true for success
*/
- public boolean startPktFateMonitoring() {
+ public boolean startPktFateMonitoring(@NonNull String ifaceName) {
synchronized (sLock) {
- if (mIWifiStaIface == null) return boolResult(false);
+ IWifiStaIface iface = getStaIface(ifaceName);
+ if (iface == null) return boolResult(false);
try {
- WifiStatus status = mIWifiStaIface.startDebugPacketFateMonitoring();
+ WifiStatus status = iface.startDebugPacketFateMonitoring();
return ok(status);
} catch (RemoteException e) {
handleRemoteException(e);
@@ -1969,16 +2066,18 @@
* <p>
* Reports the outbound frames for the most recent association (space allowing).
*
+ * @param ifaceName Name of the interface.
* @param reportBufs
* @return true for success
*/
- public boolean getTxPktFates(WifiNative.TxFateReport[] reportBufs) {
+ public boolean getTxPktFates(@NonNull String ifaceName, WifiNative.TxFateReport[] reportBufs) {
if (ArrayUtils.isEmpty(reportBufs)) return boolResult(false);
synchronized (sLock) {
- if (mIWifiStaIface == null) return boolResult(false);
+ IWifiStaIface iface = getStaIface(ifaceName);
+ if (iface == null) return boolResult(false);
try {
MutableBoolean ok = new MutableBoolean(false);
- mIWifiStaIface.getDebugTxPacketFates((status, fates) -> {
+ iface.getDebugTxPacketFates((status, fates) -> {
if (!ok(status)) return;
int i = 0;
for (WifiDebugTxPacketFateReport fate : fates) {
@@ -2009,16 +2108,18 @@
* <p>
* Reports the inbound frames for the most recent association (space allowing).
*
+ * @param ifaceName Name of the interface.
* @param reportBufs
* @return true for success
*/
- public boolean getRxPktFates(WifiNative.RxFateReport[] reportBufs) {
+ public boolean getRxPktFates(@NonNull String ifaceName, WifiNative.RxFateReport[] reportBufs) {
if (ArrayUtils.isEmpty(reportBufs)) return boolResult(false);
synchronized (sLock) {
- if (mIWifiStaIface == null) return boolResult(false);
+ IWifiStaIface iface = getStaIface(ifaceName);
+ if (iface == null) return boolResult(false);
try {
MutableBoolean ok = new MutableBoolean(false);
- mIWifiStaIface.getDebugRxPacketFates((status, fates) -> {
+ iface.getDebugRxPacketFates((status, fates) -> {
if (!ok(status)) return;
int i = 0;
for (WifiDebugRxPacketFateReport fate : fates) {
@@ -2047,6 +2148,7 @@
/**
* Start sending the specified keep alive packets periodically.
*
+ * @param ifaceName Name of the interface.
* @param slot
* @param srcMac
* @param keepAlivePacket
@@ -2054,16 +2156,18 @@
* @return 0 for success, -1 for error
*/
public int startSendingOffloadedPacket(
- int slot, byte[] srcMac, KeepalivePacketData keepAlivePacket, int periodInMs) {
+ @NonNull String ifaceName, int slot, byte[] srcMac,
+ KeepalivePacketData keepAlivePacket, int periodInMs) {
enter("slot=% periodInMs=%").c(slot).c(periodInMs).flush();
ArrayList<Byte> data = NativeUtil.byteArrayToArrayList(keepAlivePacket.data);
short protocol = (short) (keepAlivePacket.protocol);
synchronized (sLock) {
- if (mIWifiStaIface == null) return -1;
+ IWifiStaIface iface = getStaIface(ifaceName);
+ if (iface == null) return -1;
try {
- WifiStatus status = mIWifiStaIface.startSendingKeepAlivePackets(
+ WifiStatus status = iface.startSendingKeepAlivePackets(
slot,
data,
protocol,
@@ -2082,16 +2186,18 @@
/**
* Stop sending the specified keep alive packets.
*
+ * @param ifaceName Name of the interface.
* @param slot id - same as startSendingOffloadedPacket call.
* @return 0 for success, -1 for error
*/
- public int stopSendingOffloadedPacket(int slot) {
+ public int stopSendingOffloadedPacket(@NonNull String ifaceName, int slot) {
enter("slot=%").c(slot).flush();
synchronized (sLock) {
- if (mIWifiStaIface == null) return -1;
+ IWifiStaIface iface = getStaIface(ifaceName);
+ if (iface == null) return -1;
try {
- WifiStatus status = mIWifiStaIface.stopSendingKeepAlivePackets(slot);
+ WifiStatus status = iface.stopSendingKeepAlivePackets(slot);
if (!ok(status)) return -1;
return 0;
} catch (RemoteException e) {
@@ -2115,22 +2221,24 @@
/**
* Start RSSI monitoring on the currently connected access point.
*
+ * @param ifaceName Name of the interface.
* @param maxRssi Maximum RSSI threshold.
* @param minRssi Minimum RSSI threshold.
* @param rssiEventHandler Called when RSSI goes above maxRssi or below minRssi
* @return 0 for success, -1 for failure
*/
- public int startRssiMonitoring(byte maxRssi, byte minRssi,
+ public int startRssiMonitoring(@NonNull String ifaceName, byte maxRssi, byte minRssi,
WifiNative.WifiRssiEventHandler rssiEventHandler) {
enter("maxRssi=% minRssi=%").c(maxRssi).c(minRssi).flush();
if (maxRssi <= minRssi) return -1;
if (rssiEventHandler == null) return -1;
synchronized (sLock) {
- if (mIWifiStaIface == null) return -1;
+ IWifiStaIface iface = getStaIface(ifaceName);
+ if (iface == null) return -1;
try {
- mIWifiStaIface.stopRssiMonitoring(sRssiMonCmdId);
+ iface.stopRssiMonitoring(sRssiMonCmdId);
WifiStatus status;
- status = mIWifiStaIface.startRssiMonitoring(sRssiMonCmdId, maxRssi, minRssi);
+ status = iface.startRssiMonitoring(sRssiMonCmdId, maxRssi, minRssi);
if (!ok(status)) return -1;
mWifiRssiEventHandler = rssiEventHandler;
return 0;
@@ -2144,15 +2252,16 @@
/**
* Stop RSSI monitoring
*
+ * @param ifaceName Name of the interface.
* @return 0 for success, -1 for failure
*/
- public int stopRssiMonitoring() {
+ public int stopRssiMonitoring(@NonNull String ifaceName) {
synchronized (sLock) {
mWifiRssiEventHandler = null;
- if (mIWifiStaIface == null) return -1;
+ IWifiStaIface iface = getStaIface(ifaceName);
+ if (iface == null) return -1;
try {
- mIWifiStaIface.stopRssiMonitoring(sRssiMonCmdId);
- WifiStatus status = mIWifiStaIface.stopRssiMonitoring(sRssiMonCmdId);
+ WifiStatus status = iface.stopRssiMonitoring(sRssiMonCmdId);
if (!ok(status)) return -1;
return 0;
} catch (RemoteException e) {
@@ -2229,14 +2338,17 @@
/**
* Enable/Disable Neighbour discovery offload functionality in the firmware.
*
+ * @param ifaceName Name of the interface.
* @param enabled true to enable, false to disable.
+ * @return true for success, false for failure
*/
- public boolean configureNeighborDiscoveryOffload(boolean enabled) {
+ public boolean configureNeighborDiscoveryOffload(@NonNull String ifaceName, boolean enabled) {
enter("enabled=%").c(enabled).flush();
synchronized (sLock) {
- if (mIWifiStaIface == null) return boolResult(false);
+ IWifiStaIface iface = getStaIface(ifaceName);
+ if (iface == null) return boolResult(false);
try {
- WifiStatus status = mIWifiStaIface.enableNdOffload(enabled);
+ WifiStatus status = iface.enableNdOffload(enabled);
if (!ok(status)) return false;
} catch (RemoteException e) {
handleRemoteException(e);
@@ -2251,16 +2363,19 @@
/**
* Query the firmware roaming capabilities.
*
+ * @param ifaceName Name of the interface.
* @param capabilities object to be filled in
* @return true for success; false for failure
*/
- public boolean getRoamingCapabilities(WifiNative.RoamingCapabilities capabilities) {
+ public boolean getRoamingCapabilities(@NonNull String ifaceName,
+ WifiNative.RoamingCapabilities capabilities) {
synchronized (sLock) {
- if (mIWifiStaIface == null) return boolResult(false);
+ IWifiStaIface iface = getStaIface(ifaceName);
+ if (iface == null) return boolResult(false);
try {
MutableBoolean ok = new MutableBoolean(false);
WifiNative.RoamingCapabilities out = capabilities;
- mIWifiStaIface.getRoamingCapabilities((status, cap) -> {
+ iface.getRoamingCapabilities((status, cap) -> {
if (!ok(status)) return;
out.maxBlacklistSize = cap.maxBlacklistSize;
out.maxWhitelistSize = cap.maxWhitelistSize;
@@ -2277,12 +2392,14 @@
/**
* Enable/disable firmware roaming.
*
+ * @param ifaceName Name of the interface.
* @param state the intended roaming state
* @return SUCCESS, FAILURE, or BUSY
*/
- public int enableFirmwareRoaming(int state) {
+ public int enableFirmwareRoaming(@NonNull String ifaceName, int state) {
synchronized (sLock) {
- if (mIWifiStaIface == null) return WifiStatusCode.ERROR_NOT_STARTED;
+ IWifiStaIface iface = getStaIface(ifaceName);
+ if (iface == null) return WifiStatusCode.ERROR_NOT_STARTED;
try {
byte val;
switch (state) {
@@ -2297,7 +2414,7 @@
return WifiStatusCode.ERROR_INVALID_ARGS;
}
- WifiStatus status = mIWifiStaIface.setRoamingState(val);
+ WifiStatus status = iface.setRoamingState(val);
mVerboseLog.d("setRoamingState returned " + status.code);
return status.code;
} catch (RemoteException e) {
@@ -2310,12 +2427,14 @@
/**
* Set firmware roaming configurations.
*
+ * @param ifaceName Name of the interface.
* @param config new roaming configuration object
* @return true for success; false for failure
*/
- public boolean configureRoaming(WifiNative.RoamingConfig config) {
+ public boolean configureRoaming(@NonNull String ifaceName, WifiNative.RoamingConfig config) {
synchronized (sLock) {
- if (mIWifiStaIface == null) return boolResult(false);
+ IWifiStaIface iface = getStaIface(ifaceName);
+ if (iface == null) return boolResult(false);
try {
StaRoamingConfig roamingConfig = new StaRoamingConfig();
@@ -2346,7 +2465,7 @@
}
}
- WifiStatus status = mIWifiStaIface.configureRoaming(roamingConfig);
+ WifiStatus status = iface.configureRoaming(roamingConfig);
if (!ok(status)) return false;
} catch (RemoteException e) {
handleRemoteException(e);
@@ -2582,8 +2701,25 @@
// The problem here is that the two threads acquire the locks in opposite order.
// If, for example, T2.2 executes between T1.2 and 1.4, then T1 and T2
// will be deadlocked.
- eventHandler.onRingBufferData(
- ringBufferStatus(status), NativeUtil.byteArrayFromArrayList(data));
+ int sizeBefore = data.size();
+ boolean conversionFailure = false;
+ try {
+ eventHandler.onRingBufferData(
+ ringBufferStatus(status), NativeUtil.byteArrayFromArrayList(data));
+ int sizeAfter = data.size();
+ if (sizeAfter != sizeBefore) {
+ conversionFailure = true;
+ }
+ } catch (ArrayIndexOutOfBoundsException e) {
+ conversionFailure = true;
+ }
+ if (conversionFailure) {
+ Log.wtf("WifiVendorHal", "Conversion failure detected in "
+ + "onDebugRingBufferDataAvailable. "
+ + "The input ArrayList |data| is potentially corrupted. "
+ + "Starting size=" + sizeBefore + ", "
+ + "final size=" + data.size());
+ }
});
}
diff --git a/service/java/com/android/server/wifi/WificondControl.java b/service/java/com/android/server/wifi/WificondControl.java
index b6104a8..68da98f 100644
--- a/service/java/com/android/server/wifi/WificondControl.java
+++ b/service/java/com/android/server/wifi/WificondControl.java
@@ -16,19 +16,24 @@
package com.android.server.wifi;
+import android.annotation.NonNull;
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.IWifiScannerImpl;
import android.net.wifi.IWificond;
import android.net.wifi.ScanResult;
+import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiScanner;
import android.net.wifi.WifiSsid;
import android.os.Binder;
+import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
+import com.android.server.wifi.WifiNative.SoftApListener;
import com.android.server.wifi.hotspot2.NetworkDetail;
import com.android.server.wifi.util.InformationElementUtil;
import com.android.server.wifi.util.NativeUtil;
@@ -40,14 +45,17 @@
import com.android.server.wifi.wificond.PnoSettings;
import com.android.server.wifi.wificond.SingleScanSettings;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
import java.util.Set;
/**
* This class provides methods for WifiNative to send control commands to wificond.
* NOTE: This class should only be used from WifiNative.
*/
-public class WificondControl {
+public class WificondControl implements IBinder.DeathRecipient {
private boolean mVerboseLoggingEnabled = false;
private static final String TAG = "WificondControl";
@@ -64,26 +72,31 @@
// Cached wificond binder handlers.
private IWificond mWificond;
- private IClientInterface mClientInterface;
- private IApInterface mApInterface;
- private IWifiScannerImpl mWificondScanner;
- private IScanEvent mScanEventHandler;
- private IPnoScanEvent mPnoScanEventHandler;
-
- private String mClientInterfaceName;
-
+ private HashMap<String, IClientInterface> mClientInterfaces = new HashMap<>();
+ private HashMap<String, IApInterface> mApInterfaces = new HashMap<>();
+ private HashMap<String, IWifiScannerImpl> mWificondScanners = new HashMap<>();
+ private HashMap<String, IScanEvent> mScanEventHandlers = new HashMap<>();
+ private HashMap<String, IPnoScanEvent> mPnoScanEventHandlers = new HashMap<>();
+ private HashMap<String, IApInterfaceEventCallback> mApInterfaceListeners = new HashMap<>();
+ private WifiNative.WificondDeathEventHandler mDeathEventHandler;
private class ScanEventHandler extends IScanEvent.Stub {
+ private String mIfaceName;
+
+ ScanEventHandler(@NonNull String ifaceName) {
+ mIfaceName = ifaceName;
+ }
+
@Override
public void OnScanResultReady() {
Log.d(TAG, "Scan result ready event");
- mWifiMonitor.broadcastScanResultEvent(mClientInterfaceName);
+ mWifiMonitor.broadcastScanResultEvent(mIfaceName);
}
@Override
public void OnScanFailed() {
Log.d(TAG, "Scan failed event");
- mWifiMonitor.broadcastScanFailedEvent(mClientInterfaceName);
+ mWifiMonitor.broadcastScanFailedEvent(mIfaceName);
}
}
@@ -95,10 +108,16 @@
}
private class PnoScanEventHandler extends IPnoScanEvent.Stub {
+ private String mIfaceName;
+
+ PnoScanEventHandler(@NonNull String ifaceName) {
+ mIfaceName = ifaceName;
+ }
+
@Override
public void OnPnoNetworkFound() {
Log.d(TAG, "Pno scan result event");
- mWifiMonitor.broadcastPnoScanResultEvent(mClientInterfaceName);
+ mWifiMonitor.broadcastPnoScanResultEvent(mIfaceName);
mWifiInjector.getWifiMetrics().incrementPnoFoundNetworkEventCount();
}
@@ -121,6 +140,38 @@
}
}
+ /**
+ * Listener for AP Interface events.
+ */
+ private class ApInterfaceEventCallback extends IApInterfaceEventCallback.Stub {
+ private SoftApListener mSoftApListener;
+
+ ApInterfaceEventCallback(SoftApListener listener) {
+ mSoftApListener = listener;
+ }
+
+ @Override
+ public void onNumAssociatedStationsChanged(int numStations) {
+ mSoftApListener.onNumAssociatedStationsChanged(numStations);
+ }
+ }
+
+ /**
+ * Called by the binder subsystem upon remote object death.
+ * Invoke all the register death handlers and clear state.
+ */
+ @Override
+ public void binderDied() {
+ Log.e(TAG, "Wificond died!");
+ if (mDeathEventHandler != null) {
+ mDeathEventHandler.onDeath();
+ }
+ clearState();
+ // Invalidate the global wificond handle on death. Will be refereshed
+ // on the next setup call.
+ mWificond = null;
+ }
+
/** Enable or disable verbose logging of WificondControl.
* @param enable True to enable verbose logging. False to disable verbose logging.
*/
@@ -129,21 +180,70 @@
}
/**
- * Setup driver for client mode via wificond.
- * @return An IClientInterface as wificond client interface binder handler.
- * Returns null on failure.
- */
- public IClientInterface setupDriverForClientMode() {
- Log.d(TAG, "Setting up driver for client mode");
+ * Registers a death notification for wificond.
+ * @return Returns true on success.
+ */
+ public boolean registerDeathHandler(@NonNull WifiNative.WificondDeathEventHandler handler) {
+ if (mDeathEventHandler != null) {
+ Log.e(TAG, "Death handler already present");
+ return false;
+ }
+ mDeathEventHandler = handler;
+ return true;
+ }
+
+ /**
+ * Deregisters a death notification for wificond.
+ * @return Returns true on success.
+ */
+ public boolean deregisterDeathHandler() {
+ if (mDeathEventHandler == null) {
+ Log.e(TAG, "No Death handler present");
+ return false;
+ }
+ mDeathEventHandler = null;
+ return true;
+ }
+
+ /**
+ * Helper method to retrieve the global wificond handle and register for
+ * death notifications.
+ */
+ private boolean retrieveWificondAndRegisterForDeath() {
+ if (mWificond != null) {
+ Log.d(TAG, "Wificond handle already retrieved");
+ // We already have a wificond handle.
+ return true;
+ }
mWificond = mWifiInjector.makeWificond();
if (mWificond == null) {
Log.e(TAG, "Failed to get reference to wificond");
+ return false;
+ }
+ try {
+ mWificond.asBinder().linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to register death notification for wificond");
+ // The remote has already died.
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Setup interface for client mode via wificond.
+ * @return An IClientInterface as wificond client interface binder handler.
+ * Returns null on failure.
+ */
+ public IClientInterface setupInterfaceForClientMode(@NonNull String ifaceName) {
+ Log.d(TAG, "Setting up interface for client mode");
+ if (!retrieveWificondAndRegisterForDeath()) {
return null;
}
IClientInterface clientInterface = null;
try {
- clientInterface = mWificond.createClientInterface();
+ clientInterface = mWificond.createClientInterface(ifaceName);
} catch (RemoteException e1) {
Log.e(TAG, "Failed to get IClientInterface due to remote exception");
return null;
@@ -156,19 +256,21 @@
Binder.allowBlocking(clientInterface.asBinder());
// Refresh Handlers
- mClientInterface = clientInterface;
+ mClientInterfaces.put(ifaceName, clientInterface);
try {
- mClientInterfaceName = clientInterface.getInterfaceName();
- mWificondScanner = mClientInterface.getWifiScannerImpl();
- if (mWificondScanner == null) {
+ IWifiScannerImpl wificondScanner = clientInterface.getWifiScannerImpl();
+ if (wificondScanner == null) {
Log.e(TAG, "Failed to get WificondScannerImpl");
return null;
}
- Binder.allowBlocking(mWificondScanner.asBinder());
- mScanEventHandler = new ScanEventHandler();
- mWificondScanner.subscribeScanEvents(mScanEventHandler);
- mPnoScanEventHandler = new PnoScanEventHandler();
- mWificondScanner.subscribePnoScanEvents(mPnoScanEventHandler);
+ mWificondScanners.put(ifaceName, wificondScanner);
+ Binder.allowBlocking(wificondScanner.asBinder());
+ ScanEventHandler scanEventHandler = new ScanEventHandler(ifaceName);
+ mScanEventHandlers.put(ifaceName, scanEventHandler);
+ wificondScanner.subscribeScanEvents(scanEventHandler);
+ PnoScanEventHandler pnoScanEventHandler = new PnoScanEventHandler(ifaceName);
+ mPnoScanEventHandlers.put(ifaceName, pnoScanEventHandler);
+ wificondScanner.subscribePnoScanEvents(pnoScanEventHandler);
} catch (RemoteException e) {
Log.e(TAG, "Failed to refresh wificond scanner due to remote exception");
}
@@ -177,21 +279,55 @@
}
/**
- * Setup driver for softAp mode via wificond.
+ * Teardown a specific STA interface configured in wificond.
+ *
+ * @return Returns true on success.
+ */
+ public boolean tearDownClientInterface(@NonNull String ifaceName) {
+ boolean success;
+ try {
+ IWifiScannerImpl scannerImpl = mWificondScanners.get(ifaceName);
+ if (scannerImpl != null) {
+ scannerImpl.unsubscribeScanEvents();
+ scannerImpl.unsubscribePnoScanEvents();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to unsubscribe wificond scanner due to remote exception");
+ return false;
+ }
+
+ try {
+ success = mWificond.tearDownClientInterface(ifaceName);
+ } catch (RemoteException e1) {
+ Log.e(TAG, "Failed to teardown client interface due to remote exception");
+ return false;
+ }
+ if (!success) {
+ Log.e(TAG, "Failed to teardown client interface");
+ return false;
+ }
+
+ mClientInterfaces.remove(ifaceName);
+ mWificondScanners.remove(ifaceName);
+ mScanEventHandlers.remove(ifaceName);
+ mPnoScanEventHandlers.remove(ifaceName);
+ return true;
+ }
+
+ /**
+ * Setup interface for softAp mode via wificond.
* @return An IApInterface as wificond Ap interface binder handler.
* Returns null on failure.
*/
- public IApInterface setupDriverForSoftApMode() {
- Log.d(TAG, "Setting up driver for soft ap mode");
- mWificond = mWifiInjector.makeWificond();
- if (mWificond == null) {
- Log.e(TAG, "Failed to get reference to wificond");
+ public IApInterface setupInterfaceForSoftApMode(@NonNull String ifaceName) {
+ Log.d(TAG, "Setting up interface for soft ap mode");
+ if (!retrieveWificondAndRegisterForDeath()) {
return null;
}
IApInterface apInterface = null;
try {
- apInterface = mWificond.createApInterface();
+ apInterface = mWificond.createApInterface(ifaceName);
} catch (RemoteException e1) {
Log.e(TAG, "Failed to get IApInterface due to remote exception");
return null;
@@ -204,12 +340,33 @@
Binder.allowBlocking(apInterface.asBinder());
// Refresh Handlers
- mApInterface = apInterface;
-
+ mApInterfaces.put(ifaceName, apInterface);
return apInterface;
}
/**
+ * Teardown a specific AP interface configured in wificond.
+ *
+ * @return Returns true on success.
+ */
+ public boolean tearDownSoftApInterface(@NonNull String ifaceName) {
+ boolean success;
+ try {
+ success = mWificond.tearDownApInterface(ifaceName);
+ } catch (RemoteException e1) {
+ Log.e(TAG, "Failed to teardown AP interface due to remote exception");
+ return false;
+ }
+ if (!success) {
+ Log.e(TAG, "Failed to teardown AP interface");
+ return false;
+ }
+ mApInterfaces.remove(ifaceName);
+ mApInterfaceListeners.remove(ifaceName);
+ return true;
+ }
+
+ /**
* Teardown all interfaces configured in wificond.
* @return Returns true on success.
*/
@@ -217,26 +374,17 @@
Log.d(TAG, "tearing down interfaces in wificond");
// Explicitly refresh the wificodn handler because |tearDownInterfaces()|
// could be used to cleanup before we setup any interfaces.
- mWificond = mWifiInjector.makeWificond();
- if (mWificond == null) {
- Log.e(TAG, "Failed to get reference to wificond");
+ if (!retrieveWificondAndRegisterForDeath()) {
return false;
}
try {
- if (mWificondScanner != null) {
- mWificondScanner.unsubscribeScanEvents();
- mWificondScanner.unsubscribePnoScanEvents();
+ for (Map.Entry<String, IWifiScannerImpl> entry : mWificondScanners.entrySet()) {
+ entry.getValue().unsubscribeScanEvents();
+ entry.getValue().unsubscribePnoScanEvents();
}
mWificond.tearDownInterfaces();
-
- // Refresh handlers
- mClientInterface = null;
- mWificondScanner = null;
- mPnoScanEventHandler = null;
- mScanEventHandler = null;
- mApInterface = null;
-
+ clearState();
return true;
} catch (RemoteException e) {
Log.e(TAG, "Failed to tear down interfaces due to remote exception");
@@ -245,17 +393,21 @@
return false;
}
+ /** Helper function to look up the interface handle using name */
+ private IClientInterface getClientInterface(@NonNull String ifaceName) {
+ return mClientInterfaces.get(ifaceName);
+ }
+
/**
* Disable wpa_supplicant via wificond.
* @return Returns true on success.
*/
public boolean disableSupplicant() {
- if (mClientInterface == null) {
- Log.e(TAG, "No valid wificond client interface handler");
+ if (!retrieveWificondAndRegisterForDeath()) {
return false;
}
try {
- return mClientInterface.disableSupplicant();
+ return mWificond.disableSupplicant();
} catch (RemoteException e) {
Log.e(TAG, "Failed to disable supplicant due to remote exception");
}
@@ -267,13 +419,11 @@
* @return Returns true on success.
*/
public boolean enableSupplicant() {
- if (mClientInterface == null) {
- Log.e(TAG, "No valid wificond client interface handler");
+ if (!retrieveWificondAndRegisterForDeath()) {
return false;
}
-
try {
- return mClientInterface.enableSupplicant();
+ return mWificond.enableSupplicant();
} catch (RemoteException e) {
Log.e(TAG, "Failed to enable supplicant due to remote exception");
}
@@ -281,19 +431,21 @@
}
/**
- * Request signal polling to wificond.
- * Returns an SignalPollResult object.
- * Returns null on failure.
- */
- public WifiNative.SignalPollResult signalPoll() {
- if (mClientInterface == null) {
+ * Request signal polling to wificond.
+ * @param ifaceName Name of the interface.
+ * Returns an SignalPollResult object.
+ * Returns null on failure.
+ */
+ public WifiNative.SignalPollResult signalPoll(@NonNull String ifaceName) {
+ IClientInterface iface = getClientInterface(ifaceName);
+ if (iface == null) {
Log.e(TAG, "No valid wificond client interface handler");
return null;
}
int[] resultArray;
try {
- resultArray = mClientInterface.signalPoll();
+ resultArray = iface.signalPoll();
if (resultArray == null || resultArray.length != 3) {
Log.e(TAG, "Invalid signal poll result from wificond");
return null;
@@ -310,19 +462,21 @@
}
/**
- * Fetch TX packet counters on current connection from wificond.
- * Returns an TxPacketCounters object.
- * Returns null on failure.
- */
- public WifiNative.TxPacketCounters getTxPacketCounters() {
- if (mClientInterface == null) {
+ * Fetch TX packet counters on current connection from wificond.
+ * @param ifaceName Name of the interface.
+ * Returns an TxPacketCounters object.
+ * Returns null on failure.
+ */
+ public WifiNative.TxPacketCounters getTxPacketCounters(@NonNull String ifaceName) {
+ IClientInterface iface = getClientInterface(ifaceName);
+ if (iface == null) {
Log.e(TAG, "No valid wificond client interface handler");
return null;
}
int[] resultArray;
try {
- resultArray = mClientInterface.getPacketCounters();
+ resultArray = iface.getPacketCounters();
if (resultArray == null || resultArray.length != 2) {
Log.e(TAG, "Invalid signal poll result from wificond");
return null;
@@ -337,23 +491,30 @@
return counters;
}
+ /** Helper function to look up the scanner impl handle using name */
+ private IWifiScannerImpl getScannerImpl(@NonNull String ifaceName) {
+ return mWificondScanners.get(ifaceName);
+ }
+
/**
* Fetch the latest scan result from kernel via wificond.
+ * @param ifaceName Name of the interface.
* @return Returns an ArrayList of ScanDetail.
* Returns an empty ArrayList on failure.
*/
- public ArrayList<ScanDetail> getScanResults(int scanType) {
+ public ArrayList<ScanDetail> getScanResults(@NonNull String ifaceName, int scanType) {
ArrayList<ScanDetail> results = new ArrayList<>();
- if (mWificondScanner == null) {
+ IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
+ if (scannerImpl == null) {
Log.e(TAG, "No valid wificond scanner interface handler");
return results;
}
try {
NativeScanResult[] nativeResults;
if (scanType == SCAN_TYPE_SINGLE_SCAN) {
- nativeResults = mWificondScanner.getScanResults();
+ nativeResults = scannerImpl.getScanResults();
} else {
- nativeResults = mWificondScanner.getPnoScanResults();
+ nativeResults = scannerImpl.getPnoScanResults();
}
for (NativeScanResult result : nativeResults) {
WifiSsid wifiSsid = WifiSsid.createFromByteArray(result.ssid);
@@ -408,12 +569,16 @@
/**
* Start a scan using wificond for the given parameters.
+ * @param ifaceName Name of the interface.
* @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(Set<Integer> freqs, Set<String> hiddenNetworkSSIDs) {
- if (mWificondScanner == null) {
+ public boolean scan(@NonNull String ifaceName,
+ Set<Integer> freqs,
+ Set<String> hiddenNetworkSSIDs) {
+ IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
+ if (scannerImpl == null) {
Log.e(TAG, "No valid wificond scanner interface handler");
return false;
}
@@ -442,7 +607,7 @@
}
try {
- return mWificondScanner.scan(settings);
+ return scannerImpl.scan(settings);
} catch (RemoteException e1) {
Log.e(TAG, "Failed to request scan due to remote exception");
}
@@ -451,11 +616,13 @@
/**
* Start PNO scan.
+ * @param ifaceName Name of the interface.
* @param pnoSettings Pno scan configuration.
* @return true on success.
*/
- public boolean startPnoScan(WifiNative.PnoSettings pnoSettings) {
- if (mWificondScanner == null) {
+ public boolean startPnoScan(@NonNull String ifaceName, WifiNative.PnoSettings pnoSettings) {
+ IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
+ if (scannerImpl == null) {
Log.e(TAG, "No valid wificond scanner interface handler");
return false;
}
@@ -481,7 +648,7 @@
}
try {
- boolean success = mWificondScanner.startPnoScan(settings);
+ boolean success = scannerImpl.startPnoScan(settings);
mWifiInjector.getWifiMetrics().incrementPnoScanStartAttempCount();
if (!success) {
mWifiInjector.getWifiMetrics().incrementPnoScanFailedCount();
@@ -495,15 +662,17 @@
/**
* Stop PNO scan.
+ * @param ifaceName Name of the interface.
* @return true on success.
*/
- public boolean stopPnoScan() {
- if (mWificondScanner == null) {
+ public boolean stopPnoScan(@NonNull String ifaceName) {
+ IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
+ if (scannerImpl == null) {
Log.e(TAG, "No valid wificond scanner interface handler");
return false;
}
try {
- return mWificondScanner.stopPnoScan();
+ return scannerImpl.stopPnoScan();
} catch (RemoteException e1) {
Log.e(TAG, "Failed to stop pno scan due to remote exception");
}
@@ -512,17 +681,163 @@
/**
* Abort ongoing single scan.
+ * @param ifaceName Name of the interface.
*/
- public void abortScan() {
- if (mWificondScanner == null) {
+ public void abortScan(@NonNull String ifaceName) {
+ IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
+ if (scannerImpl == null) {
Log.e(TAG, "No valid wificond scanner interface handler");
return;
}
try {
- mWificondScanner.abortScan();
+ scannerImpl.abortScan();
} catch (RemoteException e1) {
Log.e(TAG, "Failed to request abortScan due to remote exception");
}
}
+ /**
+ * Query the list of valid frequencies 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.
+ * The following bands are supported:
+ * WifiScanner.WIFI_BAND_24_GHZ
+ * WifiScanner.WIFI_BAND_5_GHZ
+ * WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY
+ * @return frequencies vector of valid frequencies (MHz), or null for error.
+ * @throws IllegalArgumentException if band is not recognized.
+ */
+ public int [] getChannelsForBand(int band) {
+ if (mWificond == null) {
+ Log.e(TAG, "No valid wificond scanner interface handler");
+ return null;
+ }
+ try {
+ switch (band) {
+ case WifiScanner.WIFI_BAND_24_GHZ:
+ return mWificond.getAvailable2gChannels();
+ case WifiScanner.WIFI_BAND_5_GHZ:
+ return mWificond.getAvailable5gNonDFSChannels();
+ case WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY:
+ return mWificond.getAvailableDFSChannels();
+ default:
+ throw new IllegalArgumentException("unsupported band " + band);
+ }
+ } catch (RemoteException e1) {
+ Log.e(TAG, "Failed to request getChannelsForBand due to remote exception");
+ }
+ return null;
+ }
+
+ /** Helper function to look up the interface handle using name */
+ private IApInterface getApInterface(@NonNull String ifaceName) {
+ return mApInterfaces.get(ifaceName);
+ }
+
+ /**
+ * Start Soft AP operation using the provided configuration.
+ *
+ * @param ifaceName Name of the interface.
+ * @param config Configuration to use for the soft ap created.
+ * @param listener Callback for AP events.
+ * @return true on success, false otherwise.
+ */
+ public boolean startSoftAp(@NonNull String ifaceName,
+ WifiConfiguration config,
+ SoftApListener listener) {
+ IApInterface iface = getApInterface(ifaceName);
+ if (iface == null) {
+ Log.e(TAG, "No valid ap interface handler");
+ return false;
+ }
+ int encryptionType = getIApInterfaceEncryptionType(config);
+ try {
+ // TODO(b/67745880) Note that config.SSID is intended to be either a
+ // hex string or "double quoted".
+ // However, it seems that whatever is handing us these configurations does not obey
+ // this convention.
+ boolean success = iface.writeHostapdConfig(
+ config.SSID.getBytes(StandardCharsets.UTF_8), config.hiddenSSID,
+ config.apChannel, encryptionType,
+ (config.preSharedKey != null)
+ ? config.preSharedKey.getBytes(StandardCharsets.UTF_8)
+ : new byte[0]);
+ if (!success) {
+ Log.e(TAG, "Failed to write hostapd configuration");
+ return false;
+ }
+ IApInterfaceEventCallback callback = new ApInterfaceEventCallback(listener);
+ mApInterfaceListeners.put(ifaceName, callback);
+ success = iface.startHostapd(callback);
+ if (!success) {
+ Log.e(TAG, "Failed to start hostapd.");
+ return false;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Exception in starting soft AP: " + e);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Stop the ongoing Soft AP operation.
+ *
+ * @param ifaceName Name of the interface.
+ * @return true on success, false otherwise.
+ */
+ public boolean stopSoftAp(@NonNull String ifaceName) {
+ IApInterface iface = getApInterface(ifaceName);
+ if (iface == null) {
+ Log.e(TAG, "No valid ap interface handler");
+ return false;
+ }
+ try {
+ boolean success = iface.stopHostapd();
+ if (!success) {
+ Log.e(TAG, "Failed to stop hostapd.");
+ return false;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Exception in stopping soft AP: " + e);
+ return false;
+ }
+ mApInterfaceListeners.remove(ifaceName);
+ return true;
+ }
+
+ private static int getIApInterfaceEncryptionType(WifiConfiguration localConfig) {
+ int encryptionType;
+ switch (localConfig.getAuthType()) {
+ case WifiConfiguration.KeyMgmt.NONE:
+ encryptionType = IApInterface.ENCRYPTION_TYPE_NONE;
+ break;
+ case WifiConfiguration.KeyMgmt.WPA_PSK:
+ encryptionType = IApInterface.ENCRYPTION_TYPE_WPA;
+ break;
+ case WifiConfiguration.KeyMgmt.WPA2_PSK:
+ encryptionType = IApInterface.ENCRYPTION_TYPE_WPA2;
+ break;
+ default:
+ // We really shouldn't default to None, but this was how NetworkManagementService
+ // used to do this.
+ encryptionType = IApInterface.ENCRYPTION_TYPE_NONE;
+ break;
+ }
+ return encryptionType;
+ }
+
+ /**
+ * Clear all internal handles.
+ */
+ private void clearState() {
+ // Refresh handlers
+ mClientInterfaces.clear();
+ mWificondScanners.clear();
+ mPnoScanEventHandlers.clear();
+ mScanEventHandlers.clear();
+ mApInterfaces.clear();
+ mApInterfaceListeners.clear();
+ }
}
diff --git a/service/java/com/android/server/wifi/aware/WifiAwareClientState.java b/service/java/com/android/server/wifi/aware/WifiAwareClientState.java
index 3570f1d..987d49e 100644
--- a/service/java/com/android/server/wifi/aware/WifiAwareClientState.java
+++ b/service/java/com/android/server/wifi/aware/WifiAwareClientState.java
@@ -20,7 +20,6 @@
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
-import android.net.wifi.RttManager;
import android.net.wifi.aware.ConfigRequest;
import android.net.wifi.aware.IWifiAwareEventCallback;
import android.os.RemoteException;
@@ -271,47 +270,6 @@
}
/**
- * Called on RTT success - forwards call to client.
- */
- public void onRangingSuccess(int rangingId, RttManager.ParcelableRttResults results) {
- if (VDBG) {
- Log.v(TAG, "onRangingSuccess: rangingId=" + rangingId + ", results=" + results);
- }
- try {
- mCallback.onRangingSuccess(rangingId, results);
- } catch (RemoteException e) {
- Log.w(TAG, "onRangingSuccess: RemoteException - ignored: " + e);
- }
- }
-
- /**
- * Called on RTT failure - forwards call to client.
- */
- public void onRangingFailure(int rangingId, int reason, String description) {
- if (VDBG) {
- Log.v(TAG, "onRangingSuccess: rangingId=" + rangingId + ", reason=" + reason
- + ", description=" + description);
- }
- try {
- mCallback.onRangingFailure(rangingId, reason, description);
- } catch (RemoteException e) {
- Log.w(TAG, "onRangingFailure: RemoteException - ignored: " + e);
- }
- }
-
- /**
- * Called on RTT operation aborted - forwards call to client.
- */
- public void onRangingAborted(int rangingId) {
- if (VDBG) Log.v(TAG, "onRangingSuccess: rangingId=" + rangingId);
- try {
- mCallback.onRangingAborted(rangingId);
- } catch (RemoteException e) {
- Log.w(TAG, "onRangingAborted: RemoteException - ignored: " + e);
- }
- }
-
- /**
* Dump the internal state of the class.
*/
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
diff --git a/service/java/com/android/server/wifi/aware/WifiAwareDataPathStateManager.java b/service/java/com/android/server/wifi/aware/WifiAwareDataPathStateManager.java
index efeca65..82bc2c4 100644
--- a/service/java/com/android/server/wifi/aware/WifiAwareDataPathStateManager.java
+++ b/service/java/com/android/server/wifi/aware/WifiAwareDataPathStateManager.java
@@ -122,6 +122,7 @@
sNetworkCapabilitiesFilter
.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING)
.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
.addCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED);
sNetworkCapabilitiesFilter.setNetworkSpecifier(new MatchAllNetworkSpecifier());
diff --git a/service/java/com/android/server/wifi/aware/WifiAwareDiscoverySessionState.java b/service/java/com/android/server/wifi/aware/WifiAwareDiscoverySessionState.java
index 86f4e37..3358a4a 100644
--- a/service/java/com/android/server/wifi/aware/WifiAwareDiscoverySessionState.java
+++ b/service/java/com/android/server/wifi/aware/WifiAwareDiscoverySessionState.java
@@ -244,13 +244,20 @@
* (usually not used in the match decisions).
* @param matchFilter The filter from the discovery advertisement (which was
* used in the match decision).
+ * @param rangingIndication Bit mask indicating the type of ranging event triggered.
+ * @param rangeMm The range to the peer in mm (valid if rangingIndication specifies ingress
+ * or egress events - i.e. non-zero).
*/
public void onMatch(int requestorInstanceId, byte[] peerMac, byte[] serviceSpecificInfo,
- byte[] matchFilter) {
+ byte[] matchFilter, int rangingIndication, int rangeMm) {
int peerId = getPeerIdOrAddIfNew(requestorInstanceId, peerMac);
try {
- mCallback.onMatch(peerId, serviceSpecificInfo, matchFilter);
+ if (rangingIndication == 0) {
+ mCallback.onMatch(peerId, serviceSpecificInfo, matchFilter);
+ } else {
+ mCallback.onMatchWithDistance(peerId, serviceSpecificInfo, matchFilter, rangeMm);
+ }
} catch (RemoteException e) {
Log.w(TAG, "onMatch: RemoteException (FYI): " + e);
}
diff --git a/service/java/com/android/server/wifi/aware/WifiAwareNativeApi.java b/service/java/com/android/server/wifi/aware/WifiAwareNativeApi.java
index a6e724f..c8b5fce 100644
--- a/service/java/com/android/server/wifi/aware/WifiAwareNativeApi.java
+++ b/service/java/com/android/server/wifi/aware/WifiAwareNativeApi.java
@@ -26,6 +26,7 @@
import android.hardware.wifi.V1_0.NanInitiateDataPathRequest;
import android.hardware.wifi.V1_0.NanMatchAlg;
import android.hardware.wifi.V1_0.NanPublishRequest;
+import android.hardware.wifi.V1_0.NanRangingIndication;
import android.hardware.wifi.V1_0.NanRespondToDataPathIndicationRequest;
import android.hardware.wifi.V1_0.NanSubscribeRequest;
import android.hardware.wifi.V1_0.NanTransmitFollowupRequest;
@@ -430,11 +431,13 @@
req.baseConfigs.disableMatchExpirationIndication = true;
req.baseConfigs.disableFollowupReceivedIndication = false;
- // TODO: configure ranging and security
- req.baseConfigs.securityConfig.securityType = NanDataPathSecurityType.OPEN;
- req.baseConfigs.rangingRequired = false;
req.autoAcceptDataPathRequests = false;
+ req.baseConfigs.rangingRequired = publishConfig.mEnableRanging;
+
+ // TODO: configure security
+ req.baseConfigs.securityConfig.securityType = NanDataPathSecurityType.OPEN;
+
req.publishType = publishConfig.mPublishType;
req.txType = NanTxType.BROADCAST;
@@ -493,9 +496,23 @@
req.baseConfigs.disableMatchExpirationIndication = true;
req.baseConfigs.disableFollowupReceivedIndication = false;
- // TODO: configure ranging and security
+ req.baseConfigs.rangingRequired =
+ subscribeConfig.mMinDistanceMmSet || subscribeConfig.mMaxDistanceMmSet;
+ req.baseConfigs.configRangingIndications = 0;
+ // TODO: b/69428593 remove correction factors once HAL converted from CM to MM
+ if (subscribeConfig.mMinDistanceMmSet) {
+ req.baseConfigs.distanceIngressCm = (short) Math.min(
+ subscribeConfig.mMinDistanceMm / 10, Short.MAX_VALUE);
+ req.baseConfigs.configRangingIndications |= NanRangingIndication.INGRESS_MET_MASK;
+ }
+ if (subscribeConfig.mMaxDistanceMmSet) {
+ req.baseConfigs.distanceEgressCm = (short) Math.min(subscribeConfig.mMaxDistanceMm / 10,
+ Short.MAX_VALUE);
+ req.baseConfigs.configRangingIndications |= NanRangingIndication.EGRESS_MET_MASK;
+ }
+
+ // TODO: configure security
req.baseConfigs.securityConfig.securityType = NanDataPathSecurityType.OPEN;
- req.baseConfigs.rangingRequired = false;
req.subscribeType = subscribeConfig.mSubscribeType;
diff --git a/service/java/com/android/server/wifi/aware/WifiAwareNativeCallback.java b/service/java/com/android/server/wifi/aware/WifiAwareNativeCallback.java
index 2121160..b45978b 100644
--- a/service/java/com/android/server/wifi/aware/WifiAwareNativeCallback.java
+++ b/service/java/com/android/server/wifi/aware/WifiAwareNativeCallback.java
@@ -405,13 +405,17 @@
+ (event.serviceSpecificInfo == null ? 0 : event.serviceSpecificInfo.size())
+ ", matchFilter=" + Arrays.toString(
convertArrayListToNativeByteArray(event.matchFilter)) + ", mf.size()=" + (
- event.matchFilter == null ? 0 : event.matchFilter.size()));
+ event.matchFilter == null ? 0 : event.matchFilter.size())
+ + ", rangingIndicationType=" + event.rangingIndicationType
+ + ", rangingMeasurementInCm=" + event.rangingMeasurementInCm);
}
incrementCbCount(CB_EV_MATCH);
+ // TODO: b/69428593 get rid of conversion once HAL moves from CM to MM
mWifiAwareStateManager.onMatchNotification(event.discoverySessionId, event.peerId,
event.addr, convertArrayListToNativeByteArray(event.serviceSpecificInfo),
- convertArrayListToNativeByteArray(event.matchFilter));
+ convertArrayListToNativeByteArray(event.matchFilter), event.rangingIndicationType,
+ event.rangingMeasurementInCm * 10);
}
@Override
diff --git a/service/java/com/android/server/wifi/aware/WifiAwareNativeManager.java b/service/java/com/android/server/wifi/aware/WifiAwareNativeManager.java
index e855d81..d6bec5f 100644
--- a/service/java/com/android/server/wifi/aware/WifiAwareNativeManager.java
+++ b/service/java/com/android/server/wifi/aware/WifiAwareNativeManager.java
@@ -16,10 +16,12 @@
package com.android.server.wifi.aware;
+import android.annotation.NonNull;
import android.hardware.wifi.V1_0.IWifiNanIface;
import android.hardware.wifi.V1_0.IfaceType;
import android.hardware.wifi.V1_0.WifiStatus;
import android.hardware.wifi.V1_0.WifiStatusCode;
+import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;
@@ -41,6 +43,7 @@
private WifiAwareStateManager mWifiAwareStateManager;
private HalDeviceManager mHalDeviceManager;
+ private Handler mHandler;
private WifiAwareNativeCallback mWifiAwareNativeCallback;
private IWifiNanIface mWifiNanIface = null;
private InterfaceDestroyedListener mInterfaceDestroyedListener =
@@ -56,7 +59,13 @@
mWifiAwareNativeCallback = wifiAwareNativeCallback;
}
- public void start() {
+ /**
+ * Initialize the class - intended for late initialization.
+ *
+ * @param handler Handler on which to execute interface available callbacks.
+ */
+ public void start(Handler handler) {
+ mHandler = handler;
mHalDeviceManager.initialize();
mHalDeviceManager.registerStatusListener(
new HalDeviceManager.ManagerStatusListener() {
@@ -69,7 +78,7 @@
// 1. no problem registering duplicates - only one will be called
// 2. will be called immediately if available
mHalDeviceManager.registerInterfaceAvailableForRequestListener(
- IfaceType.NAN, mInterfaceAvailableForRequestListener, null);
+ IfaceType.NAN, mInterfaceAvailableForRequestListener, mHandler);
} else {
awareIsDown();
}
@@ -77,7 +86,7 @@
}, null);
if (mHalDeviceManager.isStarted()) {
mHalDeviceManager.registerInterfaceAvailableForRequestListener(
- IfaceType.NAN, mInterfaceAvailableForRequestListener, null);
+ IfaceType.NAN, mInterfaceAvailableForRequestListener, mHandler);
tryToGetAware();
}
}
@@ -104,7 +113,7 @@
return;
}
IWifiNanIface iface = mHalDeviceManager.createNanIface(mInterfaceDestroyedListener,
- null);
+ mHandler);
if (iface == null) {
if (DBG) Log.d(TAG, "Was not able to obtain an IWifiNanIface");
} else {
@@ -142,7 +151,7 @@
private class InterfaceDestroyedListener implements
HalDeviceManager.InterfaceDestroyedListener {
@Override
- public void onDestroyed() {
+ public void onDestroyed(@NonNull String ifaceName) {
if (DBG) Log.d(TAG, "Interface was destroyed");
awareIsDown();
}
diff --git a/service/java/com/android/server/wifi/aware/WifiAwareRttStateManager.java b/service/java/com/android/server/wifi/aware/WifiAwareRttStateManager.java
deleted file mode 100644
index 9d0441f..0000000
--- a/service/java/com/android/server/wifi/aware/WifiAwareRttStateManager.java
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wifi.aware;
-
-import android.content.Context;
-import android.net.wifi.IRttManager;
-import android.net.wifi.RttManager;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.util.Log;
-import android.util.SparseArray;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.AsyncChannel;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.Arrays;
-
-
-/**
- * Manages interactions between the Aware and the RTT service. Duplicates some of the functionality
- * of the RttManager.
- */
-public class WifiAwareRttStateManager {
- private static final String TAG = "WifiAwareRttStateMgr";
-
- private static final boolean DBG = false;
- private static final boolean VDBG = false; // STOPSHIP if true
-
- private final SparseArray<WifiAwareClientState> mPendingOperations = new SparseArray<>();
- private AsyncChannel mAsyncChannel;
- private Context mContext;
-
- /**
- * Initializes the connection to the RTT service.
- */
- public void start(Context context, Looper looper) {
- if (VDBG) Log.v(TAG, "start()");
-
- IBinder b = ServiceManager.getService(Context.WIFI_RTT_SERVICE);
- IRttManager service = IRttManager.Stub.asInterface(b);
- if (service == null) {
- Log.e(TAG, "start(): not able to get WIFI_RTT_SERVICE");
- return;
- }
-
- startWithRttService(context, looper, service);
- }
-
- /**
- * Initializes the connection to the RTT service.
- */
- @VisibleForTesting
- public void startWithRttService(Context context, Looper looper, IRttManager service) {
- Messenger messenger;
- try {
- messenger = service.getMessenger(null, new int[1]);
- } catch (RemoteException e) {
- Log.e(TAG, "start(): not able to getMessenger() of WIFI_RTT_SERVICE");
- return;
- }
-
- mAsyncChannel = new AsyncChannel();
- mAsyncChannel.connect(context, new AwareRttHandler(looper), messenger);
- mContext = context;
- }
-
- private WifiAwareClientState getAndRemovePendingOperationClient(int rangingId) {
- WifiAwareClientState client = mPendingOperations.get(rangingId);
- mPendingOperations.delete(rangingId);
- return client;
- }
-
- /**
- * Start a ranging operation for the client + peer MAC.
- */
- public void startRanging(int rangingId, WifiAwareClientState client,
- RttManager.RttParams[] params) {
- if (VDBG) {
- Log.v(TAG, "startRanging: rangingId=" + rangingId + ", parms="
- + Arrays.toString(params));
- }
-
- if (mAsyncChannel == null) {
- Log.d(TAG, "startRanging(): AsyncChannel to RTT service not configured - failing");
- client.onRangingFailure(rangingId, RttManager.REASON_NOT_AVAILABLE,
- "Aware service not able to configure connection to RTT service");
- return;
- }
-
- mPendingOperations.put(rangingId, client);
- RttManager.ParcelableRttParams pparams = new RttManager.ParcelableRttParams(params);
- mAsyncChannel.sendMessage(RttManager.CMD_OP_START_RANGING, 0, rangingId, pparams);
- }
-
- private class AwareRttHandler extends Handler {
- AwareRttHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- if (VDBG) Log.v(TAG, "handleMessage(): " + msg.what);
-
- // channel configuration messages
- switch (msg.what) {
- case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
- if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
- mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION,
- new RttManager.RttClient(mContext.getPackageName()));
- } else {
- Log.e(TAG, "Failed to set up channel connection to RTT service");
- mAsyncChannel = null;
- }
- return;
- case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED:
- /* NOP */
- return;
- case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
- Log.e(TAG, "Channel connection to RTT service lost");
- mAsyncChannel = null;
- return;
- }
-
- // RTT-specific messages
- WifiAwareClientState client = getAndRemovePendingOperationClient(msg.arg2);
- if (client == null) {
- Log.e(TAG, "handleMessage(): RTT message (" + msg.what
- + ") -- cannot find registered pending operation client for ID "
- + msg.arg2);
- return;
- }
-
- switch (msg.what) {
- case RttManager.CMD_OP_SUCCEEDED: {
- int rangingId = msg.arg2;
- RttManager.ParcelableRttResults results = (RttManager.ParcelableRttResults)
- msg.obj;
- if (VDBG) {
- Log.v(TAG, "CMD_OP_SUCCEEDED: rangingId=" + rangingId + ", results="
- + results);
- }
- for (int i = 0; i < results.mResults.length; ++i) {
- /*
- * TODO: store peer ID rather than null in the return result.
- */
- results.mResults[i].bssid = null;
- }
- client.onRangingSuccess(rangingId, results);
- break;
- }
- case RttManager.CMD_OP_FAILED: {
- int rangingId = msg.arg2;
- int reason = msg.arg1;
- String description = ((Bundle) msg.obj).getString(RttManager.DESCRIPTION_KEY);
- if (VDBG) {
- Log.v(TAG, "CMD_OP_FAILED: rangingId=" + rangingId + ", reason=" + reason
- + ", description=" + description);
- }
- client.onRangingFailure(rangingId, reason, description);
- break;
- }
- case RttManager.CMD_OP_ABORTED: {
- int rangingId = msg.arg2;
- if (VDBG) {
- Log.v(TAG, "CMD_OP_ABORTED: rangingId=" + rangingId);
- }
- client.onRangingAborted(rangingId);
- break;
- }
- default:
- Log.e(TAG, "handleMessage(): ignoring message " + msg.what);
- break;
- }
- }
- }
-
- /**
- * Dump the internal state of the class.
- */
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println("WifiAwareRttStateManager:");
- pw.println(" mPendingOperations: [" + mPendingOperations + "]");
- }
-}
diff --git a/service/java/com/android/server/wifi/aware/WifiAwareServiceImpl.java b/service/java/com/android/server/wifi/aware/WifiAwareServiceImpl.java
index b77ae63..421d9ac 100644
--- a/service/java/com/android/server/wifi/aware/WifiAwareServiceImpl.java
+++ b/service/java/com/android/server/wifi/aware/WifiAwareServiceImpl.java
@@ -16,15 +16,16 @@
package com.android.server.wifi.aware;
+import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.wifi.V1_0.NanStatusType;
-import android.net.wifi.RttManager;
import android.net.wifi.aware.Characteristics;
import android.net.wifi.aware.ConfigRequest;
import android.net.wifi.aware.DiscoverySession;
import android.net.wifi.aware.IWifiAwareDiscoverySessionCallback;
import android.net.wifi.aware.IWifiAwareEventCallback;
+import android.net.wifi.aware.IWifiAwareMacAddressProvider;
import android.net.wifi.aware.IWifiAwareManager;
import android.net.wifi.aware.PublishConfig;
import android.net.wifi.aware.SubscribeConfig;
@@ -42,7 +43,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.util.Arrays;
+import java.util.List;
/**
* Implementation of the IWifiAwareManager AIDL interface. Performs validity
@@ -63,7 +64,6 @@
private final SparseArray<IBinder.DeathRecipient> mDeathRecipientsByClientId =
new SparseArray<>();
private int mNextClientId = 1;
- private int mNextRangingId = 1;
private final SparseIntArray mUidByClientId = new SparseIntArray();
public WifiAwareServiceImpl(Context context) {
@@ -134,7 +134,7 @@
}
if (configRequest != null) {
- enforceConnectivityInternalPermission();
+ enforceNetworkStackPermission();
} else {
configRequest = new ConfigRequest.Builder().build();
}
@@ -326,7 +326,7 @@
enforceChangePermission();
if (retryCount != 0) {
- enforceConnectivityInternalPermission();
+ enforceNetworkStackPermission();
}
if (message != null
@@ -352,30 +352,10 @@
}
@Override
- public int startRanging(int clientId, int sessionId, RttManager.ParcelableRttParams params) {
- enforceAccessPermission();
- enforceLocationPermission();
+ public void requestMacAddresses(int uid, List peerIds, IWifiAwareMacAddressProvider callback) {
+ enforceNetworkStackPermission();
- // TODO: b/35676064 restricts access to this API until decide if will open.
- enforceConnectivityInternalPermission();
-
- int uid = getMockableCallingUid();
- enforceClientValidity(uid, clientId);
- if (VDBG) {
- Log.v(TAG, "startRanging: clientId=" + clientId + ", sessionId=" + sessionId + ", "
- + ", parms=" + Arrays.toString(params.mParams));
- }
-
- if (params.mParams.length == 0) {
- throw new IllegalArgumentException("Empty ranging parameters");
- }
-
- int rangingId;
- synchronized (mLock) {
- rangingId = mNextRangingId++;
- }
- mStateManager.startRanging(clientId, sessionId, params.mParams, rangingId);
- return rangingId;
+ mStateManager.requestMacAddresses(uid, peerIds, callback);
}
@Override
@@ -424,8 +404,7 @@
TAG);
}
- private void enforceConnectivityInternalPermission() {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL,
- TAG);
+ private void enforceNetworkStackPermission() {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.NETWORK_STACK, TAG);
}
}
diff --git a/service/java/com/android/server/wifi/aware/WifiAwareStateManager.java b/service/java/com/android/server/wifi/aware/WifiAwareStateManager.java
index 6ced948..89d9a90 100644
--- a/service/java/com/android/server/wifi/aware/WifiAwareStateManager.java
+++ b/service/java/com/android/server/wifi/aware/WifiAwareStateManager.java
@@ -21,11 +21,11 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.wifi.V1_0.NanStatusType;
-import android.net.wifi.RttManager;
import android.net.wifi.aware.Characteristics;
import android.net.wifi.aware.ConfigRequest;
import android.net.wifi.aware.IWifiAwareDiscoverySessionCallback;
import android.net.wifi.aware.IWifiAwareEventCallback;
+import android.net.wifi.aware.IWifiAwareMacAddressProvider;
import android.net.wifi.aware.PublishConfig;
import android.net.wifi.aware.SubscribeConfig;
import android.net.wifi.aware.WifiAwareManager;
@@ -48,7 +48,6 @@
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
import com.android.internal.util.WakeupMessage;
-import com.android.server.wifi.util.NativeUtil;
import com.android.server.wifi.util.WifiPermissionsWrapper;
import libcore.util.HexEncoding;
@@ -62,6 +61,7 @@
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
+import java.util.List;
import java.util.Map;
/**
@@ -108,7 +108,6 @@
private static final int COMMAND_TYPE_ENQUEUE_SEND_MESSAGE = 107;
private static final int COMMAND_TYPE_ENABLE_USAGE = 108;
private static final int COMMAND_TYPE_DISABLE_USAGE = 109;
- private static final int COMMAND_TYPE_START_RANGING = 110;
private static final int COMMAND_TYPE_GET_CAPABILITIES = 111;
private static final int COMMAND_TYPE_CREATE_ALL_DATA_PATH_INTERFACES = 112;
private static final int COMMAND_TYPE_DELETE_ALL_DATA_PATH_INTERFACES = 113;
@@ -167,7 +166,6 @@
private static final String MESSAGE_BUNDLE_KEY_MAC_ADDRESS = "mac_address";
private static final String MESSAGE_BUNDLE_KEY_MESSAGE_DATA = "message_data";
private static final String MESSAGE_BUNDLE_KEY_REQ_INSTANCE_ID = "req_instance_id";
- private static final String MESSAGE_BUNDLE_KEY_RANGING_ID = "ranging_id";
private static final String MESSAGE_BUNDLE_KEY_SEND_MESSAGE_ENQUEUE_TIME = "message_queue_time";
private static final String MESSAGE_BUNDLE_KEY_RETRY_COUNT = "retry_count";
private static final String MESSAGE_BUNDLE_KEY_SUCCESS_FLAG = "success_flag";
@@ -185,6 +183,8 @@
private static final String MESSAGE_BUNDLE_KEY_PMK = "pmk";
private static final String MESSAGE_BUNDLE_KEY_PASSPHRASE = "passphrase";
private static final String MESSAGE_BUNDLE_KEY_OOB = "out_of_band";
+ private static final String MESSAGE_RANGING_INDICATION = "ranging_indication";
+ private static final String MESSAGE_RANGE_MM = "range_mm";
private WifiAwareNativeApi mWifiAwareNativeApi;
private WifiAwareNativeManager mWifiAwareNativeManager;
@@ -203,7 +203,6 @@
private volatile Capabilities mCapabilities;
private volatile Characteristics mCharacteristics = null;
private WifiAwareStateMachine mSm;
- private WifiAwareRttStateManager mRtt;
public WifiAwareDataPathStateManager mDataPathMgr;
private PowerManager mPowerManager;
@@ -348,7 +347,6 @@
mSm.setDbg(DBG);
mSm.start();
- mRtt = new WifiAwareRttStateManager();
mDataPathMgr = new WifiAwareDataPathStateManager(this);
mDataPathMgr.start(mContext, mSm.getHandler().getLooper(), awareMetrics,
permissionsWrapper);
@@ -417,6 +415,48 @@
}
/*
+ * Cross-service API: synchronized but independent of state machine
+ */
+
+ /**
+ * Translate (and return in the callback) the peerId to its MAC address representation.
+ */
+ public void requestMacAddresses(int uid, List<Integer> peerIds,
+ IWifiAwareMacAddressProvider callback) {
+ mSm.getHandler().post(() -> {
+ if (VDBG) Log.v(TAG, "requestMacAddresses: uid=" + uid + ", peerIds=" + peerIds);
+ Map<Integer, byte[]> peerIdToMacMap = new HashMap<>();
+ for (int i = 0; i < mClients.size(); ++i) {
+ WifiAwareClientState client = mClients.valueAt(i);
+ if (client.getUid() != uid) {
+ continue;
+ }
+
+ SparseArray<WifiAwareDiscoverySessionState> sessions = client.getSessions();
+ for (int j = 0; j < sessions.size(); ++j) {
+ WifiAwareDiscoverySessionState session = sessions.valueAt(j);
+
+ for (int peerId : peerIds) {
+ WifiAwareDiscoverySessionState.PeerInfo peerInfo = session.getPeerInfo(
+ peerId);
+ if (peerInfo != null) {
+ peerIdToMacMap.put(peerId, peerInfo.mMac);
+ }
+ }
+ }
+ }
+
+ try {
+ if (VDBG) Log.v(TAG, "requestMacAddresses: peerIdToMacMap=" + peerIdToMacMap);
+ callback.macAddress(peerIdToMacMap);
+ } catch (RemoteException e) {
+ Log.e(TAG, "requestMacAddress (sync): exception on callback -- " + e);
+
+ }
+ });
+ }
+
+ /*
* COMMANDS
*/
@@ -553,20 +593,6 @@
}
/**
- * Place a request to range a peer on the discovery session on the state machine queue.
- */
- public void startRanging(int clientId, int sessionId, RttManager.RttParams[] params,
- int rangingId) {
- Message msg = mSm.obtainMessage(MESSAGE_TYPE_COMMAND);
- msg.arg1 = COMMAND_TYPE_START_RANGING;
- msg.arg2 = clientId;
- msg.obj = params;
- msg.getData().putInt(MESSAGE_BUNDLE_KEY_SESSION_ID, sessionId);
- msg.getData().putInt(MESSAGE_BUNDLE_KEY_RANGING_ID, rangingId);
- mSm.sendMessage(msg);
- }
-
- /**
* Enable usage of Aware. Doesn't actually turn on Aware (form clusters) - that
* only happens when a connection is created.
*/
@@ -920,7 +946,7 @@
* matching service (to the one we were looking for).
*/
public void onMatchNotification(int pubSubId, int requestorInstanceId, byte[] peerMac,
- byte[] serviceSpecificInfo, byte[] matchFilter) {
+ byte[] serviceSpecificInfo, byte[] matchFilter, int rangingIndication, int rangeMm) {
Message msg = mSm.obtainMessage(MESSAGE_TYPE_NOTIFICATION);
msg.arg1 = NOTIFICATION_TYPE_MATCH;
msg.arg2 = pubSubId;
@@ -928,6 +954,8 @@
msg.getData().putByteArray(MESSAGE_BUNDLE_KEY_MAC_ADDRESS, peerMac);
msg.getData().putByteArray(MESSAGE_BUNDLE_KEY_SSI_DATA, serviceSpecificInfo);
msg.getData().putByteArray(MESSAGE_BUNDLE_KEY_FILTER_DATA, matchFilter);
+ msg.getData().putInt(MESSAGE_RANGING_INDICATION, rangingIndication);
+ msg.getData().putInt(MESSAGE_RANGE_MM, rangeMm);
mSm.sendMessage(msg);
}
@@ -1231,9 +1259,11 @@
byte[] serviceSpecificInfo = msg.getData()
.getByteArray(MESSAGE_BUNDLE_KEY_SSI_DATA);
byte[] matchFilter = msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_FILTER_DATA);
+ int rangingIndication = msg.getData().getInt(MESSAGE_RANGING_INDICATION);
+ int rangeMm = msg.getData().getInt(MESSAGE_RANGE_MM);
onMatchLocal(pubSubId, requestorInstanceId, peerMac, serviceSpecificInfo,
- matchFilter);
+ matchFilter, rangingIndication, rangeMm);
break;
}
case NOTIFICATION_TYPE_SESSION_TERMINATED: {
@@ -1525,18 +1555,6 @@
case COMMAND_TYPE_DISABLE_USAGE:
waitForResponse = disableUsageLocal(mCurrentTransactionId);
break;
- case COMMAND_TYPE_START_RANGING: {
- Bundle data = msg.getData();
-
- int clientId = msg.arg2;
- RttManager.RttParams[] params = (RttManager.RttParams[]) msg.obj;
- int sessionId = data.getInt(MESSAGE_BUNDLE_KEY_SESSION_ID);
- int rangingId = data.getInt(MESSAGE_BUNDLE_KEY_RANGING_ID);
-
- startRangingLocal(clientId, sessionId, params, rangingId);
- waitForResponse = false;
- break;
- }
case COMMAND_TYPE_GET_CAPABILITIES:
if (mCapabilities == null) {
waitForResponse = mWifiAwareNativeApi.getCapabilities(
@@ -1613,8 +1631,7 @@
waitForResponse = endDataPathLocal(mCurrentTransactionId, msg.arg2);
break;
case COMMAND_TYPE_DELAYED_INITIALIZATION:
- mWifiAwareNativeManager.start();
- mRtt.start(mContext, mSm.getHandler().getLooper());
+ mWifiAwareNativeManager.start(getHandler());
waitForResponse = false;
break;
default:
@@ -1827,9 +1844,6 @@
case COMMAND_TYPE_DISABLE_USAGE:
Log.wtf(TAG, "processTimeout: DISABLE_USAGE - shouldn't be waiting!");
break;
- case COMMAND_TYPE_START_RANGING:
- Log.wtf(TAG, "processTimeout: START_RANGING - shouldn't be waiting!");
- break;
case COMMAND_TYPE_GET_CAPABILITIES:
Log.e(TAG,
"processTimeout: GET_CAPABILITIES timed-out - strange, will try again"
@@ -2308,49 +2322,6 @@
return callDispatched;
}
- private void startRangingLocal(int clientId, int sessionId, RttManager.RttParams[] params,
- int rangingId) {
- if (VDBG) {
- Log.v(TAG, "startRangingLocal: clientId=" + clientId + ", sessionId=" + sessionId
- + ", parms=" + Arrays.toString(params) + ", rangingId=" + rangingId);
- }
-
- WifiAwareClientState client = mClients.get(clientId);
- if (client == null) {
- Log.e(TAG, "startRangingLocal: no client exists for clientId=" + clientId);
- return;
- }
-
- WifiAwareDiscoverySessionState session = client.getSession(sessionId);
- if (session == null) {
- Log.e(TAG, "startRangingLocal: no session exists for clientId=" + clientId
- + ", sessionId=" + sessionId);
- client.onRangingFailure(rangingId, RttManager.REASON_INVALID_REQUEST,
- "Invalid session ID");
- return;
- }
-
- for (RttManager.RttParams param : params) {
- String peerIdStr = param.bssid;
- try {
- WifiAwareDiscoverySessionState.PeerInfo peerInfo = session.getPeerInfo(
- Integer.parseInt(peerIdStr));
- if (peerInfo == null || peerInfo.mMac == null) {
- Log.d(TAG, "startRangingLocal: no MAC address for peer ID=" + peerIdStr);
- param.bssid = "";
- } else {
- param.bssid = NativeUtil.macAddressFromByteArray(peerInfo.mMac);
- }
- } catch (NumberFormatException e) {
- Log.e(TAG, "startRangingLocal: invalid peer ID specification (in bssid field): '"
- + peerIdStr + "'");
- param.bssid = "";
- }
- }
-
- mRtt.startRanging(rangingId, client, params);
- }
-
private boolean initiateDataPathSetupLocal(short transactionId,
WifiAwareNetworkSpecifier networkSpecifier, int peerId, int channelRequestType,
int channel, byte[] peer, String interfaceName, byte[] pmk, String passphrase,
@@ -2823,13 +2794,14 @@
}
private void onMatchLocal(int pubSubId, int requestorInstanceId, byte[] peerMac,
- byte[] serviceSpecificInfo, byte[] matchFilter) {
+ byte[] serviceSpecificInfo, byte[] matchFilter, int rangingIndication, int rangeMm) {
if (VDBG) {
Log.v(TAG,
"onMatch: pubSubId=" + pubSubId + ", requestorInstanceId=" + requestorInstanceId
+ ", peerDiscoveryMac=" + String.valueOf(HexEncoding.encode(peerMac))
+ ", serviceSpecificInfo=" + Arrays.toString(serviceSpecificInfo)
- + ", matchFilter=" + Arrays.toString(matchFilter));
+ + ", matchFilter=" + Arrays.toString(matchFilter)
+ + ", rangingIndication=" + rangingIndication + ", rangeMm=" + rangeMm);
}
Pair<WifiAwareClientState, WifiAwareDiscoverySessionState> data =
@@ -2839,7 +2811,8 @@
return;
}
- data.second.onMatch(requestorInstanceId, peerMac, serviceSpecificInfo, matchFilter);
+ data.second.onMatch(requestorInstanceId, peerMac, serviceSpecificInfo, matchFilter,
+ rangingIndication, rangeMm);
}
private void onSessionTerminatedLocal(int pubSubId, boolean isPublish, int reason) {
@@ -3061,7 +3034,6 @@
}
pw.println(" mSettableParameters: " + mSettableParameters);
mSm.dump(fd, pw, args);
- mRtt.dump(fd, pw, args);
mDataPathMgr.dump(fd, pw, args);
mWifiAwareNativeApi.dump(fd, pw, args);
}
diff --git a/service/java/com/android/server/wifi/hotspot2/OWNERS b/service/java/com/android/server/wifi/hotspot2/OWNERS
index bea5780..08b6c9e 100644
--- a/service/java/com/android/server/wifi/hotspot2/OWNERS
+++ b/service/java/com/android/server/wifi/hotspot2/OWNERS
@@ -1 +1,2 @@
-zqiu@google.com
+sohanirao@google.com
+etancohen@google.com
diff --git a/service/java/com/android/server/wifi/hotspot2/OsuNetworkConnection.java b/service/java/com/android/server/wifi/hotspot2/OsuNetworkConnection.java
new file mode 100644
index 0000000..f1bf117
--- /dev/null
+++ b/service/java/com/android/server/wifi/hotspot2/OsuNetworkConnection.java
@@ -0,0 +1,270 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wifi.hotspot2;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.Network;
+import android.net.NetworkInfo;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.net.wifi.WifiSsid;
+import android.os.Handler;
+import android.text.TextUtils;
+import android.util.Log;
+
+/**
+ * Responsible for setup/monitor on Wi-Fi state and connection to the OSU AP.
+ */
+public class OsuNetworkConnection {
+ private static final String TAG = "OsuNetworkConnection";
+
+ private final Context mContext;
+
+ private boolean mVerboseLoggingEnabled = false;
+ private WifiManager mWifiManager;
+ private Callbacks mCallbacks;
+ private boolean mConnected = false;
+ private int mNetworkId = -1;
+ private boolean mWifiEnabled = false;
+
+ /**
+ * Callbacks on Wi-Fi connection state changes.
+ */
+ public interface Callbacks {
+ /**
+ * Invoked when network connection is established with IP connectivity.
+ *
+ * @param network {@link Network} associated with the connected network.
+ */
+ void onConnected(Network network);
+
+ /**
+ * Invoked when the targeted network is disconnected.
+ */
+ void onDisconnected();
+
+ /**
+ * Invoked when a timer tracking connection request is not reset by successfull connection.
+ */
+ void onTimeOut();
+
+ /**
+ * Invoked when Wifi is enabled.
+ */
+ void onWifiEnabled();
+
+ /**
+ * Invoked when Wifi is disabled.
+ */
+ void onWifiDisabled();
+ }
+
+ /**
+ * Create an instance of {@link NetworkConnection} for the specified Wi-Fi network.
+ * @param context The application context
+ */
+ public OsuNetworkConnection(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Called to initialize tracking of wifi state and network events by registering for the
+ * corresponding intents.
+ */
+ public void init(Handler handler) {
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+ filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
+ BroadcastReceiver receiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
+ handleNetworkStateChanged(
+ intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO),
+ intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO));
+ } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
+ int state = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
+ WifiManager.WIFI_STATE_UNKNOWN);
+ handleWifiStateChanged(state);
+ }
+ }
+ };
+ mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
+ mContext.registerReceiver(receiver, filter, null, handler);
+ mWifiEnabled = mWifiManager.isWifiEnabled();
+ }
+
+ /**
+ * Disconnect, if required in the two cases
+ * - still connected to the OSU AP
+ * - connection to OSU AP was requested and in progress
+ */
+ public void disconnectIfNeeded() {
+ if (mNetworkId < 0) {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "No connection to tear down");
+ }
+ return;
+ }
+ mWifiManager.removeNetwork(mNetworkId);
+ mNetworkId = -1;
+ mConnected = false;
+ if (mCallbacks != null) {
+ mCallbacks.onDisconnected();
+ }
+ }
+
+ /**
+ * Register for network and Wifi state events
+ * @param callbacks The callbacks to be invoked on network change events
+ */
+ public void setEventCallback(Callbacks callbacks) {
+ mCallbacks = callbacks;
+ }
+
+ /**
+ * Connect to a OSU Wi-Fi network specified by the given SSID. The security type of the Wi-Fi
+ * network is either open or OSEN (OSU Server-only authenticated layer 2 Encryption Network).
+ * When network access identifier is provided, OSEN is used.
+ *
+ * @param ssid The SSID to connect to
+ * @param nai Network access identifier of the network
+ *
+ * @return boolean true if connection was successfully initiated
+ */
+ public boolean connect(WifiSsid ssid, String nai) {
+ if (mConnected) {
+ if (mVerboseLoggingEnabled) {
+ // Already connected
+ Log.v(TAG, "Connect called twice");
+ }
+ return true;
+ }
+ if (!mWifiManager.isWifiEnabled()) {
+ Log.w(TAG, "Wifi is not enabled");
+ return false;
+ }
+ WifiConfiguration config = new WifiConfiguration();
+ config.SSID = "\"" + ssid.toString() + "\"";
+ if (TextUtils.isEmpty(nai)) {
+ config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ } else {
+ // TODO(sohanirao): Handle OSEN.
+ Log.w(TAG, "OSEN not supported");
+ return false;
+ }
+ mNetworkId = mWifiManager.addNetwork(config);
+ if (mNetworkId < 0) {
+ Log.e(TAG, "Unable to add network");
+ return false;
+ }
+ if (!mWifiManager.enableNetwork(mNetworkId, true)) {
+ Log.e(TAG, "Unable to enable network " + mNetworkId);
+ disconnectIfNeeded();
+ return false;
+ }
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "Current network ID " + mNetworkId);
+ }
+ // TODO(sohanirao): setup alarm to time out the connection attempt.
+ return true;
+ }
+
+ /**
+ * Method to update logging level in this class
+ * @param verbose more than 0 enables verbose logging
+ */
+ public void enableVerboseLogging(int verbose) {
+ mVerboseLoggingEnabled = verbose > 0 ? true : false;
+ }
+
+ /**
+ * Handle network state changed events.
+ *
+ * @param networkInfo {@link NetworkInfo} indicating the current network state
+ * @param wifiInfo {@link WifiInfo} associated with the current network when connected
+ */
+ private void handleNetworkStateChanged(NetworkInfo networkInfo, WifiInfo wifiInfo) {
+ if (networkInfo == null) {
+ Log.w(TAG, "NetworkInfo not provided for network state changed event");
+ return;
+ }
+ switch (networkInfo.getDetailedState()) {
+ case CONNECTED:
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "Connected event received");
+ }
+ if (wifiInfo == null) {
+ Log.w(TAG, "WifiInfo not provided for network state changed event");
+ return;
+ }
+ handleConnectedEvent(wifiInfo);
+ break;
+ case DISCONNECTED:
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "Disconnected event received");
+ }
+ disconnectIfNeeded();
+ break;
+ default:
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "Ignore uninterested state: " + networkInfo.getDetailedState());
+ }
+ break;
+ }
+ }
+
+ /**
+ * Handle network connected event.
+ *
+ * @param wifiInfo {@link WifiInfo} associated with the current connection
+ */
+ private void handleConnectedEvent(WifiInfo wifiInfo) {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "handleConnectedEvent " + wifiInfo.getNetworkId());
+ }
+ if (wifiInfo.getNetworkId() != mNetworkId) {
+ disconnectIfNeeded();
+ return;
+ }
+ if (!mConnected) {
+ mConnected = true;
+ if (mCallbacks != null) {
+ mCallbacks.onConnected(mWifiManager.getCurrentNetwork());
+ }
+ }
+ }
+
+ /**
+ * Handle Wifi state change event
+ */
+ private void handleWifiStateChanged(int state) {
+ if (state == WifiManager.WIFI_STATE_DISABLED && mWifiEnabled) {
+ mWifiEnabled = false;
+ if (mCallbacks != null) mCallbacks.onWifiDisabled();
+ }
+ if (state == WifiManager.WIFI_STATE_ENABLED && !mWifiEnabled) {
+ mWifiEnabled = true;
+ if (mCallbacks != null) mCallbacks.onWifiEnabled();
+ }
+ }
+}
diff --git a/service/java/com/android/server/wifi/hotspot2/PasspointManager.java b/service/java/com/android/server/wifi/hotspot2/PasspointManager.java
index 5d79ba4..fec3dd8 100644
--- a/service/java/com/android/server/wifi/hotspot2/PasspointManager.java
+++ b/service/java/com/android/server/wifi/hotspot2/PasspointManager.java
@@ -33,8 +33,10 @@
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiEnterpriseConfig;
+import android.net.wifi.hotspot2.IProvisioningCallback;
import android.net.wifi.hotspot2.OsuProvider;
import android.net.wifi.hotspot2.PasspointConfiguration;
+import android.os.Looper;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
@@ -99,6 +101,7 @@
private final WifiConfigManager mWifiConfigManager;
private final CertificateVerifier mCertVerifier;
private final WifiMetrics mWifiMetrics;
+ private final PasspointProvisioner mPasspointProvisioner;
// Counter used for assigning unique identifier to each provider.
private long mProviderIndex;
@@ -212,10 +215,27 @@
mProviderIndex = 0;
wifiConfigStore.registerStoreData(objectFactory.makePasspointConfigStoreData(
mKeyStore, mSimAccessor, new DataSourceHandler()));
+ mPasspointProvisioner = objectFactory.makePasspointProvisioner(context,
+ objectFactory.makeOsuNetworkConnection(context));
sPasspointManager = this;
}
/**
+ * Initializes the provisioning flow with a looper
+ */
+ public void initializeProvisioner(Looper looper) {
+ mPasspointProvisioner.init(looper);
+ }
+
+ /**
+ * Enable verbose logging
+ * @param verbose more than 0 enables verbose logging
+ */
+ public void enableVerboseLogging(int verbose) {
+ mPasspointProvisioner.enableVerboseLogging(verbose);
+ }
+
+ /**
* Add or update a Passpoint provider with the given configuration.
*
* Each provider is uniquely identified by its FQDN (Fully Qualified Domain Name).
@@ -325,6 +345,44 @@
* @return A pair of {@link PasspointProvider} and match status.
*/
public Pair<PasspointProvider, PasspointMatch> matchProvider(ScanResult scanResult) {
+ List<Pair<PasspointProvider, PasspointMatch>> allMatches = getAllMatchedProviders(
+ scanResult);
+ if (allMatches == null) {
+ return null;
+ }
+
+ Pair<PasspointProvider, PasspointMatch> bestMatch = null;
+ for (Pair<PasspointProvider, PasspointMatch> match : allMatches) {
+ if (match.second == PasspointMatch.HomeProvider) {
+ bestMatch = match;
+ break;
+ }
+ if (match.second == PasspointMatch.RoamingProvider && bestMatch == null) {
+ bestMatch = match;
+ }
+ }
+
+ if (bestMatch != null) {
+ Log.d(TAG, String.format("Matched %s to %s as %s", scanResult.SSID,
+ bestMatch.first.getConfig().getHomeSp().getFqdn(),
+ bestMatch.second == PasspointMatch.HomeProvider ? "Home Provider"
+ : "Roaming Provider"));
+ } else {
+ Log.d(TAG, "Match not found for " + scanResult.SSID);
+ }
+ return bestMatch;
+ }
+
+ /**
+ * Return a list of all providers that can provide service through the given AP.
+ *
+ * @param scanResult The scan result associated with the AP
+ * @return a list of pairs of {@link PasspointProvider} and match status.
+ */
+ public List<Pair<PasspointProvider, PasspointMatch>> getAllMatchedProviders(
+ ScanResult scanResult) {
+ List<Pair<PasspointProvider, PasspointMatch>> allMatches = new ArrayList<>();
+
// Retrieve the relevant information elements, mainly Roaming Consortium IE and Hotspot 2.0
// Vendor Specific IE.
InformationElementUtil.RoamingConsortium roamingConsortium =
@@ -338,7 +396,7 @@
bssid = Utils.parseMac(scanResult.BSSID);
} catch (IllegalArgumentException e) {
Log.e(TAG, "Invalid BSSID provided in the scan result: " + scanResult.BSSID);
- return null;
+ return allMatches;
}
ANQPNetworkKey anqpKey = ANQPNetworkKey.buildKey(scanResult.SSID, bssid, scanResult.hessid,
vsa.anqpDomainID);
@@ -349,30 +407,30 @@
roamingConsortium.anqpOICount > 0,
vsa.hsRelease == NetworkDetail.HSRelease.R2);
Log.d(TAG, "ANQP entry not found for: " + anqpKey);
- return null;
+ return allMatches;
}
- Pair<PasspointProvider, PasspointMatch> bestMatch = null;
for (Map.Entry<String, PasspointProvider> entry : mProviders.entrySet()) {
PasspointProvider provider = entry.getValue();
PasspointMatch matchStatus = provider.match(anqpEntry.getElements());
- if (matchStatus == PasspointMatch.HomeProvider) {
- bestMatch = Pair.create(provider, matchStatus);
- break;
- }
- if (matchStatus == PasspointMatch.RoamingProvider && bestMatch == null) {
- bestMatch = Pair.create(provider, matchStatus);
+ if (matchStatus == PasspointMatch.HomeProvider
+ || matchStatus == PasspointMatch.RoamingProvider) {
+ allMatches.add(Pair.create(provider, matchStatus));
}
}
- if (bestMatch != null) {
- Log.d(TAG, String.format("Matched %s to %s as %s", scanResult.SSID,
- bestMatch.first.getConfig().getHomeSp().getFqdn(),
- bestMatch.second == PasspointMatch.HomeProvider ? "Home Provider"
- : "Roaming Provider"));
+
+ if (allMatches.size() != 0) {
+ for (Pair<PasspointProvider, PasspointMatch> match : allMatches) {
+ Log.d(TAG, String.format("Matched %s to %s as %s", scanResult.SSID,
+ match.first.getConfig().getHomeSp().getFqdn(),
+ match.second == PasspointMatch.HomeProvider ? "Home Provider"
+ : "Roaming Provider"));
+ }
} else {
- Log.d(TAG, "Match not found for " + scanResult.SSID);
+ Log.d(TAG, "No matches not found for " + scanResult.SSID);
}
- return bestMatch;
+
+ return allMatches;
}
/**
@@ -497,6 +555,38 @@
}
/**
+ * Match the given WiFi AP to all installed Passpoint configurations. Return the list of all
+ * matching configurations (or an empty list if none).
+ *
+ * @param scanResult The scan result of the given AP
+ * @return List of {@link WifiConfiguration}
+ */
+ public List<WifiConfiguration> getAllMatchingWifiConfigs(ScanResult scanResult) {
+ if (scanResult == null) {
+ Log.e(TAG, "Attempt to get matching config for a null ScanResult");
+ return new ArrayList<WifiConfiguration>();
+ }
+ if (!scanResult.isPasspointNetwork()) {
+ Log.e(TAG, "Attempt to get matching config for a non-Passpoint AP");
+ return new ArrayList<WifiConfiguration>();
+ }
+
+ List<Pair<PasspointProvider, PasspointMatch>> matchedProviders = getAllMatchedProviders(
+ scanResult);
+ List<WifiConfiguration> configs = new ArrayList<>();
+ for (Pair<PasspointProvider, PasspointMatch> matchedProvider : matchedProviders) {
+ WifiConfiguration config = matchedProvider.first.getWifiConfig();
+ config.SSID = ScanResultUtil.createQuotedSSID(scanResult.SSID);
+ if (matchedProvider.second == PasspointMatch.HomeProvider) {
+ config.isHomeProviderNetwork = true;
+ }
+ configs.add(config);
+ }
+
+ return configs;
+ }
+
+ /**
* Return the list of Hosspot 2.0 OSU (Online Sign-Up) providers associated with the given
* AP.
*
@@ -634,4 +724,16 @@
mProviders.put(passpointConfig.getHomeSp().getFqdn(), provider);
return true;
}
+
+ /**
+ * Start the subscription provisioning flow with a provider.
+ * @param callingUid integer indicating the uid of the caller
+ * @param provider {@link OsuProvider} the provider to subscribe to
+ * @param callback {@link IProvisioningCallback} callback to update status to the caller
+ * @return boolean return value from the provisioning method
+ */
+ public boolean startSubscriptionProvisioning(int callingUid, OsuProvider provider,
+ IProvisioningCallback callback) {
+ return mPasspointProvisioner.startSubscriptionProvisioning(callingUid, provider, callback);
+ }
}
diff --git a/service/java/com/android/server/wifi/hotspot2/PasspointObjectFactory.java b/service/java/com/android/server/wifi/hotspot2/PasspointObjectFactory.java
index c41c49a..71fc47a 100644
--- a/service/java/com/android/server/wifi/hotspot2/PasspointObjectFactory.java
+++ b/service/java/com/android/server/wifi/hotspot2/PasspointObjectFactory.java
@@ -16,6 +16,7 @@
package com.android.server.wifi.hotspot2;
+import android.content.Context;
import android.net.wifi.hotspot2.PasspointConfiguration;
import com.android.server.wifi.Clock;
@@ -95,4 +96,25 @@
public CertificateVerifier makeCertificateVerifier() {
return new CertificateVerifier();
}
+
+ /**
+ * Create an instance of {@link PasspointProvisioner}.
+ *
+ * @param context
+ * @return {@link PasspointProvisioner}
+ */
+ public PasspointProvisioner makePasspointProvisioner(Context context,
+ OsuNetworkConnection osuNetworkConnection) {
+ return new PasspointProvisioner(context, osuNetworkConnection);
+ }
+
+ /**
+ * Create an instance of {@link OsuNetworkConnection}.
+ *
+ * @param context
+ * @return {@link OsuNetworkConnection}
+ */
+ public OsuNetworkConnection makeOsuNetworkConnection(Context context) {
+ return new OsuNetworkConnection(context);
+ }
}
diff --git a/service/java/com/android/server/wifi/hotspot2/PasspointProvisioner.java b/service/java/com/android/server/wifi/hotspot2/PasspointProvisioner.java
new file mode 100644
index 0000000..d3bb773
--- /dev/null
+++ b/service/java/com/android/server/wifi/hotspot2/PasspointProvisioner.java
@@ -0,0 +1,309 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wifi.hotspot2;
+
+import android.content.Context;
+import android.net.Network;
+import android.net.wifi.hotspot2.IProvisioningCallback;
+import android.net.wifi.hotspot2.OsuProvider;
+import android.net.wifi.hotspot2.ProvisioningCallback;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * Provides methods to carry out provisioning flow
+ */
+public class PasspointProvisioner {
+ private static final String TAG = "PasspointProvisioner";
+
+ private static final int PROVISIONING_STATUS = 0;
+ private static final int PROVISIONING_FAILURE = 1;
+
+ private final Context mContext;
+ private final ProvisioningStateMachine mProvisioningStateMachine;
+ private final OsuNetworkCallbacks mOsuNetworkCallbacks;
+ private final OsuNetworkConnection mOsuNetworkConnection;
+
+ private int mCallingUid;
+ private boolean mVerboseLoggingEnabled = false;
+
+ PasspointProvisioner(Context context, OsuNetworkConnection osuNetworkConnection) {
+ mContext = context;
+ mOsuNetworkConnection = osuNetworkConnection;
+ mProvisioningStateMachine = new ProvisioningStateMachine();
+ mOsuNetworkCallbacks = new OsuNetworkCallbacks();
+ }
+
+ /**
+ * Sets up for provisioning
+ * @param looper Looper on which the Provisioning state machine will run
+ */
+ public void init(Looper looper) {
+ mProvisioningStateMachine.start(new Handler(looper));
+ mOsuNetworkConnection.init(mProvisioningStateMachine.getHandler());
+ }
+
+ /**
+ * Enable verbose logging to help debug failures
+ * @param level integer indicating verbose logging enabled if > 0
+ */
+ public void enableVerboseLogging(int level) {
+ mVerboseLoggingEnabled = (level > 0) ? true : false;
+ mOsuNetworkConnection.enableVerboseLogging(level);
+ }
+
+ /**
+ * Start provisioning flow with a given provider.
+ * @param callingUid calling uid.
+ * @param provider {@link OsuProvider} to provision with.
+ * @param callback {@link IProvisioningCallback} to provide provisioning status.
+ * @return boolean value, true if provisioning was started, false otherwise.
+ *
+ * Implements HS2.0 provisioning flow with a given HS2.0 provider.
+ */
+ public boolean startSubscriptionProvisioning(int callingUid, OsuProvider provider,
+ IProvisioningCallback callback) {
+ mCallingUid = callingUid;
+
+ Log.v(TAG, "Provisioning started with " + provider.toString());
+
+ mProvisioningStateMachine.getHandler().post(() -> {
+ mProvisioningStateMachine.startProvisioning(provider, callback);
+ });
+
+ return true;
+ }
+
+ /**
+ * Handles the provisioning flow state transitions
+ */
+ class ProvisioningStateMachine {
+ private static final String TAG = "ProvisioningStateMachine";
+
+ private static final int DEFAULT_STATE = 0;
+ private static final int INITIAL_STATE = 1;
+ private static final int WAITING_TO_CONNECT = 2;
+ private static final int OSU_AP_CONNECTED = 3;
+ private static final int FAILED_STATE = 4;
+
+ private OsuProvider mOsuProvider;
+ private IProvisioningCallback mProvisioningCallback;
+ private Handler mHandler;
+ private int mState;
+
+ ProvisioningStateMachine() {
+ mState = DEFAULT_STATE;
+ }
+
+ /**
+ * Initializes and starts the state machine with a handler to handle incoming events
+ */
+ public void start(Handler handler) {
+ mHandler = handler;
+ changeState(INITIAL_STATE);
+ }
+
+ /**
+ * Returns the handler on which a runnable can be posted
+ * @return Handler State Machine's handler
+ */
+ public Handler getHandler() {
+ return mHandler;
+ }
+
+ /**
+ * Start Provisioning with the Osuprovider and invoke callbacks
+ * @param provider OsuProvider to provision with
+ * @param callback IProvisioningCallback to invoke callbacks on
+ */
+ public void startProvisioning(OsuProvider provider, IProvisioningCallback callback) {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "startProvisioning received in state=" + mState);
+ }
+ if (mState != INITIAL_STATE) {
+ Log.v(TAG, "State Machine needs to be reset before starting provisioning");
+ resetStateMachine();
+ }
+ mProvisioningCallback = callback;
+ mOsuProvider = provider;
+
+ // Register for network and wifi state events during provisioning flow
+ mOsuNetworkConnection.setEventCallback(mOsuNetworkCallbacks);
+
+ if (mOsuNetworkConnection.connect(mOsuProvider.getOsuSsid(),
+ mOsuProvider.getNetworkAccessIdentifier())) {
+ invokeProvisioningCallback(PROVISIONING_STATUS,
+ ProvisioningCallback.OSU_STATUS_AP_CONNECTING);
+ changeState(WAITING_TO_CONNECT);
+ } else {
+ invokeProvisioningCallback(PROVISIONING_FAILURE,
+ ProvisioningCallback.OSU_FAILURE_AP_CONNECTION);
+ enterFailedState();
+ }
+ }
+
+ /**
+ * Handle Wifi Disable event
+ */
+ public void handleWifiDisabled() {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "Wifi Disabled in state=" + mState);
+ }
+ if (mState == INITIAL_STATE || mState == FAILED_STATE) {
+ Log.w(TAG, "Wifi Disable unhandled in state=" + mState);
+ return;
+ }
+ invokeProvisioningCallback(PROVISIONING_FAILURE,
+ ProvisioningCallback.OSU_FAILURE_AP_CONNECTION);
+ enterFailedState();
+ }
+
+ private void resetStateMachine() {
+ // Set to null so that no callbacks are invoked during reset
+ mProvisioningCallback = null;
+ if (mState != INITIAL_STATE || mState != FAILED_STATE) {
+ // Transition through Failed state to clean up
+ enterFailedState();
+ }
+ changeState(INITIAL_STATE);
+ }
+
+ /**
+ * Connected event received
+ * @param network Network object for this connection
+ */
+ public void handleConnectedEvent(Network network) {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "Connected event received in state=" + mState);
+ }
+ if (mState != WAITING_TO_CONNECT) {
+ // Not waiting for a connection
+ Log.w(TAG, "Connection event unhandled in state=" + mState);
+ return;
+ }
+ invokeProvisioningCallback(PROVISIONING_STATUS,
+ ProvisioningCallback.OSU_STATUS_AP_CONNECTED);
+ changeState(OSU_AP_CONNECTED);
+ }
+
+ /**
+ * Disconnect event received
+ */
+ public void handleDisconnect() {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "Connection failed in state=" + mState);
+ }
+ if (mState == INITIAL_STATE || mState == FAILED_STATE) {
+ Log.w(TAG, "Disconnect event unhandled in state=" + mState);
+ return;
+ }
+ invokeProvisioningCallback(PROVISIONING_FAILURE,
+ ProvisioningCallback.OSU_FAILURE_AP_CONNECTION);
+ enterFailedState();
+ }
+
+ private void changeState(int nextState) {
+ if (nextState != mState) {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "Changing state from " + mState + " -> " + nextState);
+ }
+ mState = nextState;
+ }
+ }
+
+ private void invokeProvisioningCallback(int callbackType, int status) {
+ if (mProvisioningCallback == null) {
+ Log.e(TAG, "Provisioning callback " + callbackType + " with status " + status
+ + " not invoked, callback is null");
+ return;
+ }
+ try {
+ if (callbackType == PROVISIONING_STATUS) {
+ mProvisioningCallback.onProvisioningStatus(status);
+ } else {
+ mProvisioningCallback.onProvisioningFailure(status);
+ }
+ } catch (RemoteException e) {
+ if (callbackType == PROVISIONING_STATUS) {
+ Log.e(TAG, "Remote Exception while posting Provisioning status " + status);
+ } else {
+ Log.e(TAG, "Remote Exception while posting Provisioning failure " + status);
+ }
+ }
+ }
+
+ private void enterFailedState() {
+ changeState(FAILED_STATE);
+ mOsuNetworkConnection.setEventCallback(null);
+ mOsuNetworkConnection.disconnectIfNeeded();
+ }
+ }
+
+ /**
+ * Callbacks for network and wifi events
+ */
+ class OsuNetworkCallbacks implements OsuNetworkConnection.Callbacks {
+
+ OsuNetworkCallbacks() {
+ }
+
+ @Override
+ public void onConnected(Network network) {
+ Log.v(TAG, "onConnected to " + network);
+ if (network == null) {
+ mProvisioningStateMachine.getHandler().post(() -> {
+ mProvisioningStateMachine.handleDisconnect();
+ });
+ } else {
+ mProvisioningStateMachine.getHandler().post(() -> {
+ mProvisioningStateMachine.handleConnectedEvent(network);
+ });
+ }
+ }
+
+ @Override
+ public void onDisconnected() {
+ Log.v(TAG, "onDisconnected");
+ mProvisioningStateMachine.getHandler().post(() -> {
+ mProvisioningStateMachine.handleDisconnect();
+ });
+ }
+
+ @Override
+ public void onTimeOut() {
+ Log.v(TAG, "Timed out waiting for connection to OSU AP");
+ mProvisioningStateMachine.getHandler().post(() -> {
+ mProvisioningStateMachine.handleDisconnect();
+ });
+ }
+
+ @Override
+ public void onWifiEnabled() {
+ Log.v(TAG, "onWifiEnabled");
+ }
+
+ @Override
+ public void onWifiDisabled() {
+ Log.v(TAG, "onWifiDisabled");
+ mProvisioningStateMachine.getHandler().post(() -> {
+ mProvisioningStateMachine.handleWifiDisabled();
+ });
+ }
+ }
+}
diff --git a/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java b/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java
index fa16253..751737f 100644
--- a/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java
+++ b/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java
@@ -16,6 +16,7 @@
package com.android.server.wifi.p2p;
+import android.annotation.NonNull;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
@@ -524,12 +525,12 @@
}
mHalDeviceManager = mWifiInjector.getHalDeviceManager();
}
- mIWifiP2pIface = mHalDeviceManager.createP2pIface(() -> {
+ mIWifiP2pIface = mHalDeviceManager.createP2pIface((@NonNull String ifaceName) -> {
if (DBG) Log.d(TAG, "IWifiP2pIface destroyedListener");
synchronized (mLock) {
mIWifiP2pIface = null;
}
- }, mP2pStateMachine.getHandler().getLooper());
+ }, mP2pStateMachine.getHandler());
}
return messenger;
diff --git a/service/java/com/android/server/wifi/rtt/RttNative.java b/service/java/com/android/server/wifi/rtt/RttNative.java
new file mode 100644
index 0000000..e920310
--- /dev/null
+++ b/service/java/com/android/server/wifi/rtt/RttNative.java
@@ -0,0 +1,330 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wifi.rtt;
+
+import android.hardware.wifi.V1_0.IWifiRttController;
+import android.hardware.wifi.V1_0.IWifiRttControllerEventCallback;
+import android.hardware.wifi.V1_0.RttBw;
+import android.hardware.wifi.V1_0.RttConfig;
+import android.hardware.wifi.V1_0.RttPeerType;
+import android.hardware.wifi.V1_0.RttPreamble;
+import android.hardware.wifi.V1_0.RttResult;
+import android.hardware.wifi.V1_0.RttType;
+import android.hardware.wifi.V1_0.WifiChannelWidthInMhz;
+import android.hardware.wifi.V1_0.WifiStatus;
+import android.hardware.wifi.V1_0.WifiStatusCode;
+import android.net.wifi.rtt.RangingRequest;
+import android.net.wifi.rtt.RangingResult;
+import android.net.wifi.rtt.ResponderConfig;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.server.wifi.HalDeviceManager;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * TBD
+ */
+public class RttNative extends IWifiRttControllerEventCallback.Stub {
+ private static final String TAG = "RttNative";
+ private static final boolean VDBG = false; // STOPSHIP if true
+
+ private final RttServiceImpl mRttService;
+ private final HalDeviceManager mHalDeviceManager;
+
+ private Object mLock = new Object();
+
+ private IWifiRttController mIWifiRttController;
+
+ public RttNative(RttServiceImpl rttService, HalDeviceManager halDeviceManager) {
+ mRttService = rttService;
+ mHalDeviceManager = halDeviceManager;
+ }
+
+ /**
+ * Initialize the object - registering with the HAL device manager.
+ */
+ public void start() {
+ synchronized (mLock) {
+ mHalDeviceManager.initialize();
+ mHalDeviceManager.registerStatusListener(() -> {
+ if (VDBG) Log.d(TAG, "hdm.onStatusChanged");
+ updateController();
+ }, null);
+ updateController();
+ }
+ }
+
+ /**
+ * Returns true if Wi-Fi is ready for RTT requests, false otherwise.
+ */
+ public boolean isReady() {
+ synchronized (mLock) {
+ return mIWifiRttController != null;
+ }
+ }
+
+ private void updateController() {
+ if (VDBG) Log.v(TAG, "updateController: mIWifiRttController=" + mIWifiRttController);
+
+ // only care about isStarted (Wi-Fi started) not isReady - since if not
+ // ready then Wi-Fi will also be down.
+ synchronized (mLock) {
+ if (mHalDeviceManager.isStarted()) {
+ if (mIWifiRttController == null) {
+ mIWifiRttController = mHalDeviceManager.createRttController();
+ if (mIWifiRttController == null) {
+ Log.e(TAG, "updateController: Failed creating RTT controller - but Wifi is "
+ + "started!");
+ } else {
+ try {
+ mIWifiRttController.registerEventCallback(this);
+ } catch (RemoteException e) {
+ Log.e(TAG, "updateController: exception registering callback: " + e);
+ mIWifiRttController = null;
+ }
+ }
+ }
+ } else {
+ mIWifiRttController = null;
+ }
+
+ if (mIWifiRttController == null) {
+ mRttService.disable();
+ } else {
+ mRttService.enable();
+ }
+ }
+ }
+
+ /**
+ * Issue a range request to the HAL.
+ *
+ * @param cmdId Command ID for the request. Will be used in the corresponding
+ * {@link #onResults(int, ArrayList)}.
+ * @param request Range request.
+ * @return Success status: true for success, false for failure.
+ */
+ public boolean rangeRequest(int cmdId, RangingRequest request) {
+ if (VDBG) Log.v(TAG, "rangeRequest: cmdId=" + cmdId + ", request=" + request);
+ synchronized (mLock) {
+ if (!isReady()) {
+ Log.e(TAG, "rangeRequest: RttController is null");
+ return false;
+ }
+
+ ArrayList<RttConfig> rttConfig = convertRangingRequestToRttConfigs(request);
+ if (rttConfig == null) {
+ Log.e(TAG, "rangeRequest: invalid request parameters");
+ return false;
+ }
+
+ try {
+ WifiStatus status = mIWifiRttController.rangeRequest(cmdId, rttConfig);
+ if (status.code != WifiStatusCode.SUCCESS) {
+ Log.e(TAG, "rangeRequest: cannot issue range request -- code=" + status.code);
+ return false;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "rangeRequest: exception issuing range request: " + e);
+ return false;
+ }
+
+ return true;
+ }
+ }
+
+ /**
+ * Cancel an outstanding ranging request: no guarantees of execution - we will ignore any
+ * results which are returned for the canceled request.
+ *
+ * @param cmdId The cmdId issued with the original rangeRequest command.
+ * @param macAddresses A list of MAC addresses for which to cancel the operation.
+ * @return Success status: true for success, false for failure.
+ */
+ public boolean rangeCancel(int cmdId, ArrayList<byte[]> macAddresses) {
+ if (VDBG) Log.v(TAG, "rangeCancel: cmdId=" + cmdId);
+ synchronized (mLock) {
+ if (!isReady()) {
+ Log.e(TAG, "rangeCancel: RttController is null");
+ return false;
+ }
+
+ try {
+ WifiStatus status = mIWifiRttController.rangeCancel(cmdId, macAddresses);
+ if (status.code != WifiStatusCode.SUCCESS) {
+ Log.e(TAG, "rangeCancel: cannot issue range cancel -- code=" + status.code);
+ return false;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "rangeCancel: exception issuing range cancel: " + e);
+ return false;
+ }
+
+ return true;
+ }
+ }
+
+ /**
+ * Callback from HAL with range results.
+ *
+ * @param cmdId Command ID specified in the original request
+ * {@link #rangeRequest(int, RangingRequest)}.
+ * @param halResults A list of range results.
+ */
+ @Override
+ public void onResults(int cmdId, ArrayList<RttResult> halResults) {
+ if (VDBG) Log.v(TAG, "onResults: cmdId=" + cmdId + ", # of results=" + halResults.size());
+ List<RangingResult> results = new ArrayList<>(halResults.size());
+
+ mRttService.onRangingResults(cmdId, halResults);
+ }
+
+ private static ArrayList<RttConfig> convertRangingRequestToRttConfigs(RangingRequest request) {
+ ArrayList<RttConfig> rttConfigs = new ArrayList<>(request.mRttPeers.size());
+
+ // Skipping any configurations which have an error (printing out a message).
+ // The caller will only get results for valid configurations.
+ for (ResponderConfig responder: request.mRttPeers) {
+ RttConfig config = new RttConfig();
+
+ if (responder.macAddress.length != config.addr.length) {
+ Log.e(TAG, "Invalid configuration: unexpected BSSID length -- " + responder);
+ continue;
+ }
+ System.arraycopy(responder.macAddress, 0, config.addr, 0, config.addr.length);
+
+ try {
+ config.type = responder.supports80211mc ? RttType.TWO_SIDED : RttType.ONE_SIDED;
+ config.peer = halRttPeerTypeFromResponderType(responder.responderType);
+ config.channel.width = halChannelWidthFromResponderChannelWidth(
+ responder.channelWidth);
+ config.channel.centerFreq = responder.frequency;
+ config.channel.centerFreq0 = responder.centerFreq0;
+ config.channel.centerFreq1 = responder.centerFreq1;
+ config.bw = halRttChannelBandwidthFromResponderChannelWidth(responder.channelWidth);
+ config.preamble = halRttPreambleFromResponderPreamble(responder.preamble);
+
+ config.mustRequestLci = false;
+ config.mustRequestLcr = false;
+ if (config.peer == RttPeerType.NAN) {
+ config.burstPeriod = 0;
+ config.numBurst = 0;
+ config.numFramesPerBurst = 5;
+ config.numRetriesPerRttFrame = 3;
+ config.numRetriesPerFtmr = 3;
+ config.burstDuration = 15;
+ } else { // AP + all non-NAN requests
+ config.burstPeriod = 0;
+ config.numBurst = 0;
+ config.numFramesPerBurst = 8;
+ config.numRetriesPerRttFrame = 0;
+ config.numRetriesPerFtmr = 0;
+ config.burstDuration = 15;
+ }
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Invalid configuration: " + e.getMessage());
+ continue;
+ }
+
+ rttConfigs.add(config);
+ }
+
+ return rttConfigs;
+ }
+
+ static int halRttPeerTypeFromResponderType(int responderType) {
+ switch (responderType) {
+ case ResponderConfig.RESPONDER_AP:
+ return RttPeerType.AP;
+ case ResponderConfig.RESPONDER_STA:
+ return RttPeerType.STA;
+ case ResponderConfig.RESPONDER_P2P_GO:
+ return RttPeerType.P2P_GO;
+ case ResponderConfig.RESPONDER_P2P_CLIENT:
+ return RttPeerType.P2P_CLIENT;
+ case ResponderConfig.RESPONDER_AWARE:
+ return RttPeerType.NAN;
+ default:
+ throw new IllegalArgumentException(
+ "halRttPeerTypeFromResponderType: bad " + responderType);
+ }
+ }
+
+ static int halChannelWidthFromResponderChannelWidth(int responderChannelWidth) {
+ switch (responderChannelWidth) {
+ case ResponderConfig.CHANNEL_WIDTH_20MHZ:
+ return WifiChannelWidthInMhz.WIDTH_20;
+ case ResponderConfig.CHANNEL_WIDTH_40MHZ:
+ return WifiChannelWidthInMhz.WIDTH_40;
+ case ResponderConfig.CHANNEL_WIDTH_80MHZ:
+ return WifiChannelWidthInMhz.WIDTH_80;
+ case ResponderConfig.CHANNEL_WIDTH_160MHZ:
+ return WifiChannelWidthInMhz.WIDTH_160;
+ case ResponderConfig.CHANNEL_WIDTH_80MHZ_PLUS_MHZ:
+ return WifiChannelWidthInMhz.WIDTH_80P80;
+ default:
+ throw new IllegalArgumentException(
+ "halChannelWidthFromResponderChannelWidth: bad " + responderChannelWidth);
+ }
+ }
+
+ static int halRttChannelBandwidthFromResponderChannelWidth(int responderChannelWidth) {
+ switch (responderChannelWidth) {
+ case ResponderConfig.CHANNEL_WIDTH_20MHZ:
+ return RttBw.BW_20MHZ;
+ case ResponderConfig.CHANNEL_WIDTH_40MHZ:
+ return RttBw.BW_40MHZ;
+ case ResponderConfig.CHANNEL_WIDTH_80MHZ:
+ return RttBw.BW_80MHZ;
+ case ResponderConfig.CHANNEL_WIDTH_160MHZ:
+ return RttBw.BW_160MHZ;
+ case ResponderConfig.CHANNEL_WIDTH_80MHZ_PLUS_MHZ:
+ return RttBw.BW_160MHZ;
+ default:
+ throw new IllegalArgumentException(
+ "halRttChannelBandwidthFromHalBandwidth: bad " + responderChannelWidth);
+ }
+ }
+
+ static int halRttPreambleFromResponderPreamble(int responderPreamble) {
+ switch (responderPreamble) {
+ case ResponderConfig.PREAMBLE_LEGACY:
+ return RttPreamble.LEGACY;
+ case ResponderConfig.PREAMBLE_HT:
+ return RttPreamble.HT;
+ case ResponderConfig.PREAMBLE_VHT:
+ return RttPreamble.VHT;
+ default:
+ throw new IllegalArgumentException(
+ "halRttPreambleFromResponderPreamble: bad " + responderPreamble);
+ }
+ }
+
+ /**
+ * Dump the internal state of the class.
+ */
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("RttNative:");
+ pw.println(" mHalDeviceManager: " + mHalDeviceManager);
+ pw.println(" mIWifiRttController: " + mIWifiRttController);
+ }
+}
diff --git a/service/java/com/android/server/wifi/rtt/RttService.java b/service/java/com/android/server/wifi/rtt/RttService.java
new file mode 100644
index 0000000..5c2cec1
--- /dev/null
+++ b/service/java/com/android/server/wifi/rtt/RttService.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wifi.rtt;
+
+import android.content.Context;
+import android.net.wifi.aware.IWifiAwareManager;
+import android.os.HandlerThread;
+import android.os.ServiceManager;
+import android.util.Log;
+
+import com.android.server.SystemService;
+import com.android.server.wifi.HalDeviceManager;
+import com.android.server.wifi.WifiInjector;
+import com.android.server.wifi.util.WifiPermissionsUtil;
+
+/**
+ * TBD.
+ */
+public class RttService extends SystemService {
+ private static final String TAG = "RttService";
+ private Context mContext;
+ private RttServiceImpl mImpl;
+
+ public RttService(Context context) {
+ super(context);
+ mContext = context;
+ mImpl = new RttServiceImpl(context);
+ }
+
+ @Override
+ public void onStart() {
+ Log.i(TAG, "Registering " + Context.WIFI_RTT2_SERVICE);
+ publishBinderService(Context.WIFI_RTT2_SERVICE, mImpl);
+ }
+
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
+ Log.i(TAG, "Starting " + Context.WIFI_RTT2_SERVICE);
+
+ WifiInjector wifiInjector = WifiInjector.getInstance();
+ if (wifiInjector == null) {
+ Log.e(TAG, "onBootPhase(PHASE_SYSTEM_SERVICES_READY): NULL injector!");
+ return;
+ }
+
+ HalDeviceManager halDeviceManager = wifiInjector.getHalDeviceManager();
+ HandlerThread handlerThread = wifiInjector.getRttHandlerThread();
+ WifiPermissionsUtil wifiPermissionsUtil = wifiInjector.getWifiPermissionsUtil();
+
+ IWifiAwareManager awareBinder = (IWifiAwareManager) ServiceManager.getService(
+ Context.WIFI_AWARE_SERVICE);
+
+ RttNative rttNative = new RttNative(mImpl, halDeviceManager);
+ mImpl.start(handlerThread.getLooper(), wifiInjector.getClock(), awareBinder, rttNative,
+ wifiPermissionsUtil);
+ }
+ }
+}
diff --git a/service/java/com/android/server/wifi/rtt/RttServiceImpl.java b/service/java/com/android/server/wifi/rtt/RttServiceImpl.java
new file mode 100644
index 0000000..ff722ae
--- /dev/null
+++ b/service/java/com/android/server/wifi/rtt/RttServiceImpl.java
@@ -0,0 +1,891 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wifi.rtt;
+
+import android.app.ActivityManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.hardware.wifi.V1_0.RttResult;
+import android.hardware.wifi.V1_0.RttStatus;
+import android.net.wifi.aware.IWifiAwareMacAddressProvider;
+import android.net.wifi.aware.IWifiAwareManager;
+import android.net.wifi.rtt.IRttCallback;
+import android.net.wifi.rtt.IWifiRttManager;
+import android.net.wifi.rtt.RangingRequest;
+import android.net.wifi.rtt.RangingResult;
+import android.net.wifi.rtt.RangingResultCallback;
+import android.net.wifi.rtt.ResponderConfig;
+import android.net.wifi.rtt.WifiRttManager;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.WorkSource;
+import android.util.Log;
+import android.util.SparseIntArray;
+
+import com.android.internal.util.WakeupMessage;
+import com.android.server.wifi.Clock;
+import com.android.server.wifi.util.WifiPermissionsUtil;
+
+import libcore.util.HexEncoding;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+
+/**
+ * Implementation of the IWifiRttManager AIDL interface and of the RttService state manager.
+ */
+public class RttServiceImpl extends IWifiRttManager.Stub {
+ private static final String TAG = "RttServiceImpl";
+ private static final boolean VDBG = false; // STOPSHIP if true
+
+ private final Context mContext;
+ private Clock mClock;
+ private IWifiAwareManager mAwareBinder;
+ private RttNative mRttNative;
+ private WifiPermissionsUtil mWifiPermissionsUtil;
+ private ActivityManager mActivityManager;
+ private PowerManager mPowerManager;
+
+ private RttServiceSynchronized mRttServiceSynchronized;
+
+ /* package */ static final String HAL_RANGING_TIMEOUT_TAG = TAG + " HAL Ranging Timeout";
+
+ private static final long HAL_RANGING_TIMEOUT_MS = 5_000; // 5 sec
+
+ // TODO: b/69323456 convert to a settable value
+ /* package */ static final long BACKGROUND_PROCESS_EXEC_GAP_MS = 1_800_000; // 30 min
+
+ // arbitrary, larger than anything reasonable
+ /* package */ static final int MAX_QUEUED_PER_UID = 20;
+
+ public RttServiceImpl(Context context) {
+ mContext = context;
+ }
+
+ /*
+ * INITIALIZATION
+ */
+
+ /**
+ * Initializes the RTT service (usually with objects from an injector).
+ *
+ * @param looper The looper on which to synchronize operations.
+ * @param clock A mockable clock.
+ * @param awareBinder The Wi-Fi Aware service (binder) if supported on the system.
+ * @param rttNative The Native interface to the HAL.
+ * @param wifiPermissionsUtil Utility for permission checks.
+ */
+ public void start(Looper looper, Clock clock, IWifiAwareManager awareBinder,
+ RttNative rttNative,
+ WifiPermissionsUtil wifiPermissionsUtil) {
+ mClock = clock;
+ mAwareBinder = awareBinder;
+ mRttNative = rttNative;
+ mWifiPermissionsUtil = wifiPermissionsUtil;
+ mRttServiceSynchronized = new RttServiceSynchronized(looper, rttNative);
+
+ mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
+ mPowerManager = mContext.getSystemService(PowerManager.class);
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
+ mContext.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (VDBG) Log.v(TAG, "BroadcastReceiver: action=" + action);
+
+ if (PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)) {
+ if (mPowerManager.isDeviceIdleMode()) {
+ disable();
+ } else {
+ enable();
+ }
+ }
+ }
+ }, intentFilter);
+
+ mRttServiceSynchronized.mHandler.post(() -> {
+ rttNative.start();
+ });
+ }
+
+ /*
+ * ASYNCHRONOUS DOMAIN - can be called from different threads!
+ */
+
+ /**
+ * Proxy for the final native call of the parent class. Enables mocking of
+ * the function.
+ */
+ public int getMockableCallingUid() {
+ return getCallingUid();
+ }
+
+ /**
+ * Enable the API: broadcast notification
+ */
+ public void enable() {
+ if (VDBG) Log.v(TAG, "enable");
+ sendRttStateChangedBroadcast(true);
+ mRttServiceSynchronized.mHandler.post(() -> {
+ // queue should be empty at this point (but this call allows validation)
+ mRttServiceSynchronized.executeNextRangingRequestIfPossible(false);
+ });
+ }
+
+ /**
+ * Disable the API:
+ * - Clean-up (fail) pending requests
+ * - Broadcast notification
+ */
+ public void disable() {
+ if (VDBG) Log.v(TAG, "disable");
+ sendRttStateChangedBroadcast(false);
+ mRttServiceSynchronized.mHandler.post(() -> {
+ mRttServiceSynchronized.cleanUpOnDisable();
+ });
+ }
+
+ /**
+ * Binder interface API to indicate whether the API is currently available. This requires an
+ * immediate asynchronous response.
+ */
+ @Override
+ public boolean isAvailable() {
+ return mRttNative.isReady() && !mPowerManager.isDeviceIdleMode();
+ }
+
+ /**
+ * Binder interface API to start a ranging operation. Called on binder thread, operations needs
+ * to be posted to handler thread.
+ */
+ @Override
+ public void startRanging(IBinder binder, String callingPackage, WorkSource workSource,
+ RangingRequest request, IRttCallback callback) throws RemoteException {
+ if (VDBG) {
+ Log.v(TAG, "startRanging: binder=" + binder + ", callingPackage=" + callingPackage
+ + ", workSource=" + workSource + ", request=" + request + ", callback="
+ + callback);
+ }
+ // verify arguments
+ if (binder == null) {
+ throw new IllegalArgumentException("Binder must not be null");
+ }
+ if (request == null || request.mRttPeers == null || request.mRttPeers.size() == 0) {
+ throw new IllegalArgumentException("Request must not be null or empty");
+ }
+ if (callback == null) {
+ throw new IllegalArgumentException("Callback must not be null");
+ }
+ request.enforceValidity(mAwareBinder != null);
+
+ if (!isAvailable()) {
+ try {
+ callback.onRangingFailure(RangingResultCallback.STATUS_CODE_FAIL_RTT_NOT_AVAILABLE);
+ } catch (RemoteException e) {
+ Log.e(TAG, "startRanging: disabled, callback failed -- " + e);
+ }
+ return;
+ }
+
+ final int uid = getMockableCallingUid();
+
+ // permission checks
+ enforceAccessPermission();
+ enforceChangePermission();
+ enforceLocationPermission(callingPackage, uid);
+ if (workSource != null) {
+ enforceLocationHardware();
+ }
+
+ // register for binder death
+ IBinder.DeathRecipient dr = new IBinder.DeathRecipient() {
+ @Override
+ public void binderDied() {
+ if (VDBG) Log.v(TAG, "binderDied: uid=" + uid);
+ binder.unlinkToDeath(this, 0);
+
+ mRttServiceSynchronized.mHandler.post(() -> {
+ mRttServiceSynchronized.cleanUpClientRequests(uid, null);
+ });
+ }
+ };
+
+ try {
+ binder.linkToDeath(dr, 0);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error on linkToDeath - " + e);
+ }
+
+
+ mRttServiceSynchronized.mHandler.post(() -> {
+ WorkSource sourceToUse = workSource;
+ if (workSource == null || workSource.size() == 0 || workSource.get(0) == 0) {
+ sourceToUse = new WorkSource(uid);
+ }
+ mRttServiceSynchronized.queueRangingRequest(uid, sourceToUse, binder, dr,
+ callingPackage, request, callback);
+ });
+ }
+
+ @Override
+ public void cancelRanging(WorkSource workSource) throws RemoteException {
+ if (VDBG) Log.v(TAG, "cancelRanging: workSource=" + workSource);
+ enforceLocationHardware();
+
+ if (workSource == null || workSource.size() == 0 || workSource.get(0) == 0) {
+ Log.e(TAG, "cancelRanging: invalid work-source -- " + workSource);
+ return;
+ }
+
+ mRttServiceSynchronized.mHandler.post(() -> {
+ mRttServiceSynchronized.cleanUpClientRequests(0, workSource);
+ });
+ }
+
+ /**
+ * Called by HAL to report ranging results. Called on HAL thread - needs to post to local
+ * thread.
+ */
+ public void onRangingResults(int cmdId, List<RttResult> results) {
+ if (VDBG) Log.v(TAG, "onRangingResults: cmdId=" + cmdId);
+ mRttServiceSynchronized.mHandler.post(() -> {
+ mRttServiceSynchronized.onRangingResults(cmdId, results);
+ });
+ }
+
+ private void enforceAccessPermission() {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE, TAG);
+ }
+
+ private void enforceChangePermission() {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE, TAG);
+ }
+
+ private void enforceLocationPermission(String callingPackage, int uid) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
+ TAG);
+ }
+
+ private void enforceLocationHardware() {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.LOCATION_HARDWARE,
+ TAG);
+ }
+
+ private void sendRttStateChangedBroadcast(boolean enabled) {
+ if (VDBG) Log.v(TAG, "sendRttStateChangedBroadcast: enabled=" + enabled);
+ final Intent intent = new Intent(WifiRttManager.ACTION_WIFI_RTT_STATE_CHANGED);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+ }
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) {
+ pw.println("Permission Denial: can't dump RttService from pid="
+ + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
+ return;
+ }
+ pw.println("Wi-Fi RTT Service");
+ mRttServiceSynchronized.dump(fd, pw, args);
+ }
+
+ /*
+ * SYNCHRONIZED DOMAIN
+ */
+
+ /**
+ * RTT service implementation - synchronized on a single thread. All commands should be posted
+ * to the exposed handler.
+ */
+ private class RttServiceSynchronized {
+ public Handler mHandler;
+
+ private RttNative mRttNative;
+ private int mNextCommandId = 1000;
+ private Map<Integer, RttRequesterInfo> mRttRequesterInfo = new HashMap<>();
+ private List<RttRequestInfo> mRttRequestQueue = new LinkedList<>();
+ private WakeupMessage mRangingTimeoutMessage = null;
+
+ RttServiceSynchronized(Looper looper, RttNative rttNative) {
+ mRttNative = rttNative;
+
+ mHandler = new Handler(looper);
+ mRangingTimeoutMessage = new WakeupMessage(mContext, mHandler,
+ HAL_RANGING_TIMEOUT_TAG, () -> {
+ timeoutRangingRequest();
+ });
+ }
+
+ private void cancelRanging(RttRequestInfo rri) {
+ ArrayList<byte[]> macAddresses = new ArrayList<>();
+ for (ResponderConfig peer : rri.request.mRttPeers) {
+ if (peer.macAddress.length != 6) {
+ Log.e(TAG, "Invalid configuration: unexpected BSSID length -- " + peer);
+ continue;
+ }
+ macAddresses.add(peer.macAddress);
+ }
+
+ mRttNative.rangeCancel(rri.cmdId, macAddresses);
+ }
+
+ private void cleanUpOnDisable() {
+ if (VDBG) Log.v(TAG, "RttServiceSynchronized.cleanUpOnDisable");
+ for (RttRequestInfo rri : mRttRequestQueue) {
+ try {
+ if (rri.dispatchedToNative) {
+ // may not be necessary in some cases (e.g. Wi-Fi disable may already clear
+ // up active RTT), but in other cases will be needed (doze disabling RTT
+ // but Wi-Fi still up). Doesn't hurt - worst case will fail.
+ cancelRanging(rri);
+ }
+ rri.callback.onRangingFailure(
+ RangingResultCallback.STATUS_CODE_FAIL_RTT_NOT_AVAILABLE);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RttServiceSynchronized.startRanging: disabled, callback failed -- "
+ + e);
+ }
+ rri.binder.unlinkToDeath(rri.dr, 0);
+ }
+ mRttRequestQueue.clear();
+ mRangingTimeoutMessage.cancel();
+ }
+
+ /**
+ * Remove entries related to the specified client and cancel any dispatched to HAL
+ * requests. Expected to provide either the UID or the WorkSource (the other will be 0 or
+ * null respectively).
+ *
+ * A workSource specification will be cleared from the requested workSource and the request
+ * cancelled only if there are no remaining uids in the work-source.
+ */
+ private void cleanUpClientRequests(int uid, WorkSource workSource) {
+ if (VDBG) {
+ Log.v(TAG, "RttServiceSynchronized.cleanUpOnClientDeath: uid=" + uid
+ + ", workSource=" + workSource + ", mRttRequestQueue=" + mRttRequestQueue);
+ }
+ boolean dispatchedRequestAborted = false;
+ ListIterator<RttRequestInfo> it = mRttRequestQueue.listIterator();
+ while (it.hasNext()) {
+ RttRequestInfo rri = it.next();
+
+ boolean match = rri.uid == uid; // original UID will never be 0
+ if (rri.workSource != null && workSource != null) {
+ try {
+ rri.workSource.remove(workSource);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Invalid WorkSource specified in the start or cancel requests: "
+ + e);
+ }
+ if (rri.workSource.size() == 0) {
+ match = true;
+ }
+ }
+
+ if (match) {
+ if (!rri.dispatchedToNative) {
+ it.remove();
+ rri.binder.unlinkToDeath(rri.dr, 0);
+ } else {
+ dispatchedRequestAborted = true;
+ Log.d(TAG, "Client death - cancelling RTT operation in progress: cmdId="
+ + rri.cmdId);
+ mRangingTimeoutMessage.cancel();
+ cancelRanging(rri);
+ }
+ }
+ }
+
+ if (VDBG) {
+ Log.v(TAG, "RttServiceSynchronized.cleanUpOnClientDeath: uid=" + uid
+ + ", dispatchedRequestAborted=" + dispatchedRequestAborted
+ + ", after cleanup - mRttRequestQueue=" + mRttRequestQueue);
+ }
+
+ if (dispatchedRequestAborted) {
+ executeNextRangingRequestIfPossible(true);
+ }
+ }
+
+ private void timeoutRangingRequest() {
+ if (VDBG) {
+ Log.v(TAG, "RttServiceSynchronized.timeoutRangingRequest mRttRequestQueue="
+ + mRttRequestQueue);
+ }
+ if (mRttRequestQueue.size() == 0) {
+ Log.w(TAG, "RttServiceSynchronized.timeoutRangingRequest: but nothing in queue!?");
+ return;
+ }
+ RttRequestInfo rri = mRttRequestQueue.get(0);
+ if (!rri.dispatchedToNative) {
+ Log.w(TAG, "RttServiceSynchronized.timeoutRangingRequest: command not dispatched "
+ + "to native!?");
+ return;
+ }
+ cancelRanging(rri);
+ try {
+ rri.callback.onRangingFailure(RangingResultCallback.STATUS_CODE_FAIL);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RttServiceSynchronized.timeoutRangingRequest: callback failed: " + e);
+ }
+ executeNextRangingRequestIfPossible(true);
+ }
+
+ private void queueRangingRequest(int uid, WorkSource workSource, IBinder binder,
+ IBinder.DeathRecipient dr, String callingPackage, RangingRequest request,
+ IRttCallback callback) {
+ if (isRequestorSpamming(workSource)) {
+ Log.w(TAG,
+ "Work source " + workSource + " is spamming, dropping request: " + request);
+ binder.unlinkToDeath(dr, 0);
+ try {
+ callback.onRangingFailure(RangingResultCallback.STATUS_CODE_FAIL);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RttServiceSynchronized.queueRangingRequest: spamming, callback "
+ + "failed -- " + e);
+ }
+ return;
+ }
+
+ RttRequestInfo newRequest = new RttRequestInfo();
+ newRequest.uid = uid;
+ newRequest.workSource = workSource;
+ newRequest.binder = binder;
+ newRequest.dr = dr;
+ newRequest.callingPackage = callingPackage;
+ newRequest.request = request;
+ newRequest.callback = callback;
+ mRttRequestQueue.add(newRequest);
+
+ if (VDBG) {
+ Log.v(TAG, "RttServiceSynchronized.queueRangingRequest: newRequest=" + newRequest);
+ }
+
+ executeNextRangingRequestIfPossible(false);
+ }
+
+ private boolean isRequestorSpamming(WorkSource ws) {
+ if (VDBG) Log.v(TAG, "isRequestorSpamming: ws" + ws);
+
+ SparseIntArray counts = new SparseIntArray();
+
+ for (RttRequestInfo rri : mRttRequestQueue) {
+ for (int i = 0; i < rri.workSource.size(); ++i) {
+ int uid = rri.workSource.get(i);
+ counts.put(uid, counts.get(uid) + 1);
+ }
+ }
+
+ for (int i = 0; i < ws.size(); ++i) {
+ if (counts.get(ws.get(i)) < MAX_QUEUED_PER_UID) {
+ return false;
+ }
+ }
+
+ if (VDBG) {
+ Log.v(TAG, "isRequestorSpamming: ws=" + ws + ", someone is spamming: " + counts);
+ }
+ return true;
+ }
+
+ private void executeNextRangingRequestIfPossible(boolean popFirst) {
+ if (VDBG) Log.v(TAG, "executeNextRangingRequestIfPossible: popFirst=" + popFirst);
+
+ if (popFirst) {
+ if (mRttRequestQueue.size() == 0) {
+ Log.w(TAG, "executeNextRangingRequestIfPossible: pop requested - but empty "
+ + "queue!? Ignoring pop.");
+ } else {
+ RttRequestInfo topOfQueueRequest = mRttRequestQueue.remove(0);
+ topOfQueueRequest.binder.unlinkToDeath(topOfQueueRequest.dr, 0);
+ }
+ }
+
+ if (mRttRequestQueue.size() == 0) {
+ if (VDBG) Log.v(TAG, "executeNextRangingRequestIfPossible: no requests pending");
+ return;
+ }
+
+ // if top of list is in progress then do nothing
+ RttRequestInfo nextRequest = mRttRequestQueue.get(0);
+ if (nextRequest.peerHandlesTranslated || nextRequest.dispatchedToNative) {
+ if (VDBG) {
+ Log.v(TAG, "executeNextRangingRequestIfPossible: called but a command is "
+ + "executing. topOfQueue=" + nextRequest);
+ }
+ return;
+ }
+
+ startRanging(nextRequest);
+ }
+
+ private void startRanging(RttRequestInfo nextRequest) {
+ if (VDBG) {
+ Log.v(TAG, "RttServiceSynchronized.startRanging: nextRequest=" + nextRequest);
+ }
+
+ if (!isAvailable()) {
+ Log.d(TAG, "RttServiceSynchronized.startRanging: disabled");
+ try {
+ nextRequest.callback.onRangingFailure(
+ RangingResultCallback.STATUS_CODE_FAIL_RTT_NOT_AVAILABLE);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RttServiceSynchronized.startRanging: disabled, callback failed -- "
+ + e);
+ executeNextRangingRequestIfPossible(true);
+ return;
+ }
+ }
+
+ if (processAwarePeerHandles(nextRequest)) {
+ if (VDBG) {
+ Log.v(TAG, "RttServiceSynchronized.startRanging: deferring due to PeerHandle "
+ + "Aware requests");
+ }
+ return;
+ }
+
+ if (!preExecThrottleCheck(nextRequest.workSource)) {
+ Log.w(TAG, "RttServiceSynchronized.startRanging: execution throttled - nextRequest="
+ + nextRequest + ", mRttRequesterInfo=" + mRttRequesterInfo);
+ try {
+ nextRequest.callback.onRangingFailure(RangingResultCallback.STATUS_CODE_FAIL);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RttServiceSynchronized.startRanging: throttled, callback failed -- "
+ + e);
+ }
+ executeNextRangingRequestIfPossible(true);
+ return;
+ }
+
+ nextRequest.cmdId = mNextCommandId++;
+ if (mRttNative.rangeRequest(nextRequest.cmdId, nextRequest.request)) {
+ mRangingTimeoutMessage.schedule(
+ mClock.getElapsedSinceBootMillis() + HAL_RANGING_TIMEOUT_MS);
+ } else {
+ Log.w(TAG, "RttServiceSynchronized.startRanging: native rangeRequest call failed");
+ try {
+ nextRequest.callback.onRangingFailure(RangingResultCallback.STATUS_CODE_FAIL);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RttServiceSynchronized.startRanging: HAL request failed, callback "
+ + "failed -- " + e);
+ }
+ executeNextRangingRequestIfPossible(true);
+ }
+ nextRequest.dispatchedToNative = true;
+ }
+
+ /**
+ * Perform pre-execution throttling checks:
+ * - If all uids in ws are in background then check last execution and block if request is
+ * more frequent than permitted
+ * - If executing (i.e. permitted) then update execution time
+ *
+ * Returns true to permit execution, false to abort it.
+ */
+ private boolean preExecThrottleCheck(WorkSource ws) {
+ if (VDBG) Log.v(TAG, "preExecThrottleCheck: ws=" + ws);
+
+ // are all UIDs running in the background or is at least 1 in the foreground?
+ boolean allUidsInBackground = true;
+ for (int i = 0; i < ws.size(); ++i) {
+ int uidImportance = mActivityManager.getUidImportance(ws.get(i));
+ if (VDBG) {
+ Log.v(TAG, "preExecThrottleCheck: uid=" + ws.get(i) + " -> importance="
+ + uidImportance);
+ }
+ if (uidImportance
+ <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE) {
+ allUidsInBackground = false;
+ break;
+ }
+ }
+
+ // if all UIDs are in background then check timestamp since last execution and see if
+ // any is permitted (infrequent enough)
+ boolean allowExecution = false;
+ long mostRecentExecutionPermitted =
+ mClock.getElapsedSinceBootMillis() - BACKGROUND_PROCESS_EXEC_GAP_MS;
+ if (allUidsInBackground) {
+ for (int i = 0; i < ws.size(); ++i) {
+ RttRequesterInfo info = mRttRequesterInfo.get(ws.get(i));
+ if (info == null || info.lastRangingExecuted < mostRecentExecutionPermitted) {
+ allowExecution = true;
+ break;
+ }
+ }
+ } else {
+ allowExecution = true;
+ }
+
+ // update exec time
+ if (allowExecution) {
+ for (int i = 0; i < ws.size(); ++i) {
+ RttRequesterInfo info = mRttRequesterInfo.get(ws.get(i));
+ if (info == null) {
+ info = new RttRequesterInfo();
+ mRttRequesterInfo.put(ws.get(i), info);
+ }
+ info.lastRangingExecuted = mClock.getElapsedSinceBootMillis();
+ }
+ }
+
+ return allowExecution;
+ }
+
+ /**
+ * Check request for any PeerHandle Aware requests. If there are any: issue requests to
+ * translate the peer ID to a MAC address and abort current execution of the range request.
+ * The request will be re-attempted when response is received.
+ *
+ * In cases of failure: pop the current request and execute the next one. Failures:
+ * - Not able to connect to remote service (unlikely)
+ * - Request already processed: but we're missing information
+ *
+ * @return true if need to abort execution, false otherwise.
+ */
+ private boolean processAwarePeerHandles(RttRequestInfo request) {
+ List<Integer> peerIdsNeedingTranslation = new ArrayList<>();
+ for (ResponderConfig rttPeer : request.request.mRttPeers) {
+ if (rttPeer.peerHandle != null && rttPeer.macAddress == null) {
+ peerIdsNeedingTranslation.add(rttPeer.peerHandle.peerId);
+ }
+ }
+
+ if (peerIdsNeedingTranslation.size() == 0) {
+ return false;
+ }
+
+ if (request.peerHandlesTranslated) {
+ Log.w(TAG, "processAwarePeerHandles: request=" + request
+ + ": PeerHandles translated - but information still missing!?");
+ try {
+ request.callback.onRangingFailure(RangingResultCallback.STATUS_CODE_FAIL);
+ } catch (RemoteException e) {
+ Log.e(TAG, "processAwarePeerHandles: onRangingResults failure -- " + e);
+ }
+ executeNextRangingRequestIfPossible(true);
+ return true; // an abort because we removed request and are executing next one
+ }
+
+ request.peerHandlesTranslated = true;
+ try {
+ mAwareBinder.requestMacAddresses(request.uid, peerIdsNeedingTranslation,
+ new IWifiAwareMacAddressProvider.Stub() {
+ @Override
+ public void macAddress(Map peerIdToMacMap) {
+ // ASYNC DOMAIN
+ mHandler.post(() -> {
+ // BACK TO SYNC DOMAIN
+ processReceivedAwarePeerMacAddresses(request, peerIdToMacMap);
+ });
+ }
+ });
+ } catch (RemoteException e1) {
+ Log.e(TAG,
+ "processAwarePeerHandles: exception while calling requestMacAddresses -- "
+ + e1 + ", aborting request=" + request);
+ try {
+ request.callback.onRangingFailure(RangingResultCallback.STATUS_CODE_FAIL);
+ } catch (RemoteException e2) {
+ Log.e(TAG, "processAwarePeerHandles: onRangingResults failure -- " + e2);
+ }
+ executeNextRangingRequestIfPossible(true);
+ return true; // an abort because we removed request and are executing next one
+ }
+
+ return true; // a deferral
+ }
+
+ private void processReceivedAwarePeerMacAddresses(RttRequestInfo request,
+ Map<Integer, byte[]> peerIdToMacMap) {
+ if (VDBG) {
+ Log.v(TAG, "processReceivedAwarePeerMacAddresses: request=" + request
+ + ", peerIdToMacMap=" + peerIdToMacMap);
+ }
+
+ for (ResponderConfig rttPeer: request.request.mRttPeers) {
+ if (rttPeer.peerHandle != null && rttPeer.macAddress == null) {
+ rttPeer.macAddress = peerIdToMacMap.get(rttPeer.peerHandle.peerId);
+ }
+ }
+
+ // run request again
+ startRanging(request);
+ }
+
+ private void onRangingResults(int cmdId, List<RttResult> results) {
+ if (mRttRequestQueue.size() == 0) {
+ Log.e(TAG, "RttServiceSynchronized.onRangingResults: no current RTT request "
+ + "pending!?");
+ return;
+ }
+ mRangingTimeoutMessage.cancel();
+ RttRequestInfo topOfQueueRequest = mRttRequestQueue.get(0);
+
+ if (VDBG) {
+ Log.v(TAG, "RttServiceSynchronized.onRangingResults: cmdId=" + cmdId
+ + ", topOfQueueRequest=" + topOfQueueRequest + ", results="
+ + Arrays.toString(results.toArray()));
+ }
+
+ if (topOfQueueRequest.cmdId != cmdId) {
+ Log.e(TAG, "RttServiceSynchronized.onRangingResults: cmdId=" + cmdId
+ + ", does not match pending RTT request cmdId=" + topOfQueueRequest.cmdId);
+ return;
+ }
+
+ boolean permissionGranted = mWifiPermissionsUtil.checkCallersLocationPermission(
+ topOfQueueRequest.callingPackage, topOfQueueRequest.uid);
+ try {
+ if (permissionGranted) {
+ List<RangingResult> finalResults = postProcessResults(topOfQueueRequest.request,
+ results);
+ if (VDBG) {
+ Log.v(TAG, "RttServiceSynchronized.onRangingResults: finalResults="
+ + finalResults);
+ }
+ topOfQueueRequest.callback.onRangingResults(finalResults);
+ } else {
+ Log.w(TAG, "RttServiceSynchronized.onRangingResults: location permission "
+ + "revoked - not forwarding results");
+ topOfQueueRequest.callback.onRangingFailure(
+ RangingResultCallback.STATUS_CODE_FAIL);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG,
+ "RttServiceSynchronized.onRangingResults: callback exception -- " + e);
+ }
+
+ executeNextRangingRequestIfPossible(true);
+ }
+
+ /*
+ * Post process the results:
+ * - For requests without results: add FAILED results
+ * - For Aware requests using PeerHandle: replace MAC address with PeerHandle
+ * - Effectively: throws away results which don't match requests
+ */
+ private List<RangingResult> postProcessResults(RangingRequest request,
+ List<RttResult> results) {
+ Map<String, RttResult> resultEntries = new HashMap<>();
+ for (RttResult result: results) {
+ resultEntries.put(new String(HexEncoding.encode(result.addr)), result);
+ }
+
+ List<RangingResult> finalResults = new ArrayList<>(request.mRttPeers.size());
+
+ for (ResponderConfig peer: request.mRttPeers) {
+ RttResult resultForRequest = resultEntries.get(
+ new String(HexEncoding.encode(peer.macAddress)));
+ if (resultForRequest == null) {
+ if (VDBG) {
+ Log.v(TAG, "postProcessResults: missing=" + new String(
+ HexEncoding.encode(peer.macAddress)));
+ }
+ if (peer.peerHandle == null) {
+ finalResults.add(
+ new RangingResult(RangingResult.STATUS_FAIL, peer.macAddress, 0, 0,
+ 0, 0));
+ } else {
+ finalResults.add(
+ new RangingResult(RangingResult.STATUS_FAIL, peer.peerHandle, 0, 0,
+ 0, 0));
+ }
+ } else {
+ int status = resultForRequest.status == RttStatus.SUCCESS
+ ? RangingResult.STATUS_SUCCESS : RangingResult.STATUS_FAIL;
+ if (peer.peerHandle == null) {
+ finalResults.add(
+ new RangingResult(status, peer.macAddress,
+ resultForRequest.distanceInMm,
+ resultForRequest.distanceSdInMm,
+ resultForRequest.rssi, resultForRequest.timeStampInUs));
+ } else {
+ finalResults.add(
+ new RangingResult(status, peer.peerHandle,
+ resultForRequest.distanceInMm,
+ resultForRequest.distanceSdInMm,
+ resultForRequest.rssi, resultForRequest.timeStampInUs));
+ }
+ }
+ }
+
+ return finalResults;
+ }
+
+ // dump call (asynchronous most likely)
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println(" mNextCommandId: " + mNextCommandId);
+ pw.println(" mRttRequesterInfo: " + mRttRequesterInfo);
+ pw.println(" mRttRequestQueue: " + mRttRequestQueue);
+ pw.println(" mRangingTimeoutMessage: " + mRangingTimeoutMessage);
+ mRttNative.dump(fd, pw, args);
+ }
+ }
+
+ private static class RttRequestInfo {
+ public int uid;
+ public WorkSource workSource;
+ public IBinder binder;
+ public IBinder.DeathRecipient dr;
+ public String callingPackage;
+ public RangingRequest request;
+ public IRttCallback callback;
+
+ public int cmdId = 0; // uninitialized cmdId value
+ public boolean dispatchedToNative = false;
+ public boolean peerHandlesTranslated = false;
+
+ @Override
+ public String toString() {
+ return new StringBuilder("RttRequestInfo: uid=").append(uid).append(
+ ", workSource=").append(workSource).append(", binder=").append(binder).append(
+ ", dr=").append(dr).append(", callingPackage=").append(callingPackage).append(
+ ", request=").append(request.toString()).append(", callback=").append(
+ callback).append(", cmdId=").append(cmdId).append(
+ ", peerHandlesTranslated=").append(peerHandlesTranslated).toString();
+ }
+ }
+
+ private static class RttRequesterInfo {
+ public long lastRangingExecuted;
+
+ @Override
+ public String toString() {
+ return new StringBuilder("RttRequesterInfo: lastRangingExecuted=").append(
+ lastRangingExecuted).toString();
+ }
+ }
+}
diff --git a/service/java/com/android/server/wifi/scanner/ChannelHelper.java b/service/java/com/android/server/wifi/scanner/ChannelHelper.java
index d87df07..6a01f0c 100644
--- a/service/java/com/android/server/wifi/scanner/ChannelHelper.java
+++ b/service/java/com/android/server/wifi/scanner/ChannelHelper.java
@@ -242,7 +242,7 @@
if (scanSettings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) {
return toString(scanSettings.channels);
} else {
- return toString(scanSettings.band);
+ return bandToString(scanSettings.band);
}
}
@@ -255,7 +255,7 @@
if (bucketSettings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) {
return toString(bucketSettings.channels, bucketSettings.num_channels);
} else {
- return toString(bucketSettings.band);
+ return bandToString(bucketSettings.band);
}
}
@@ -293,7 +293,10 @@
return sb.toString();
}
- private static String toString(int band) {
+ /**
+ * Converts a WifiScanner.WIFI_BAND_* constant to a meaningful String
+ */
+ public static String bandToString(int band) {
switch (band) {
case WifiScanner.WIFI_BAND_UNSPECIFIED:
return "unspecified";
@@ -310,7 +313,6 @@
case WifiScanner.WIFI_BAND_BOTH_WITH_DFS:
return "24Ghz & 5Ghz (DFS incl)";
}
-
return "invalid band";
}
}
diff --git a/service/java/com/android/server/wifi/scanner/HalWifiScannerImpl.java b/service/java/com/android/server/wifi/scanner/HalWifiScannerImpl.java
index 7d0ccba..1478a99 100644
--- a/service/java/com/android/server/wifi/scanner/HalWifiScannerImpl.java
+++ b/service/java/com/android/server/wifi/scanner/HalWifiScannerImpl.java
@@ -46,7 +46,7 @@
public HalWifiScannerImpl(Context context, WifiNative wifiNative, WifiMonitor wifiMonitor,
Looper looper, Clock clock) {
mWifiNative = wifiNative;
- mChannelHelper = new HalChannelHelper(wifiNative);
+ mChannelHelper = new WificondChannelHelper(wifiNative);
mWificondScannerDelegate =
new WificondScannerImpl(context, wifiNative, wifiMonitor, mChannelHelper,
looper, clock);
@@ -131,11 +131,6 @@
}
@Override
- public boolean shouldScheduleBackgroundScanForHwPno() {
- return mWificondScannerDelegate.shouldScheduleBackgroundScanForHwPno();
- }
-
- @Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
mWificondScannerDelegate.dump(fd, pw, args);
}
diff --git a/service/java/com/android/server/wifi/scanner/NoBandChannelHelper.java b/service/java/com/android/server/wifi/scanner/NoBandChannelHelper.java
deleted file mode 100644
index b2eeada..0000000
--- a/service/java/com/android/server/wifi/scanner/NoBandChannelHelper.java
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wifi.scanner;
-
-import android.net.wifi.WifiScanner;
-import android.util.ArraySet;
-
-import com.android.server.wifi.WifiNative;
-
-import java.util.Set;
-
-/**
- * ChannelHelper that offers channel manipulation utilities when the channels in a band are not
- * known. Operations performed may simplify any band to include all channels.
- */
-public class NoBandChannelHelper extends ChannelHelper {
-
- /**
- * These parameters are used to estimate the scan duration.
- * This is a guess at the number of channels the device supports for use when a ScanSettings
- * specifies a band instead of a list of channels.
- */
- private static final int ALL_BAND_CHANNEL_COUNT_ESTIMATE = 36;
-
- @Override
- public boolean settingsContainChannel(WifiScanner.ScanSettings settings, int channel) {
- if (settings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) {
- for (int i = 0; i < settings.channels.length; ++i) {
- if (settings.channels[i].frequency == channel) {
- return true;
- }
- }
- return false;
- } else {
- return true;
- }
- }
-
- @Override
- public WifiScanner.ChannelSpec[] getAvailableScanChannels(int band) {
- return NO_CHANNELS; // not supported
- }
-
- @Override
- public int estimateScanDuration(WifiScanner.ScanSettings settings) {
- if (settings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) {
- return settings.channels.length * SCAN_PERIOD_PER_CHANNEL_MS;
- } else {
- return ALL_BAND_CHANNEL_COUNT_ESTIMATE * SCAN_PERIOD_PER_CHANNEL_MS;
- }
- }
-
- /**
- * ChannelCollection that merges channels without knowing which channels are in each band. In
- * order to do this if any band is added or the maxChannels is exceeded then all channels will
- * be included.
- */
- public class NoBandChannelCollection extends ChannelCollection {
- private final ArraySet<Integer> mChannels = new ArraySet<Integer>();
- private boolean mAllChannels = false;
-
- @Override
- public void addChannel(int frequency) {
- mChannels.add(frequency);
- }
-
- @Override
- public void addBand(int band) {
- if (band != WifiScanner.WIFI_BAND_UNSPECIFIED) {
- mAllChannels = true;
- }
- }
-
- @Override
- public boolean containsChannel(int channel) {
- return mAllChannels || mChannels.contains(channel);
- }
-
- @Override
- public boolean containsBand(int band) {
- if (band != WifiScanner.WIFI_BAND_UNSPECIFIED) {
- return mAllChannels;
- }
- return false;
- }
-
- @Override
- public boolean partiallyContainsBand(int band) {
- // We don't need to partially collapse settings in wificond scanner because we
- // don't have any limitation on the number of channels that can be scanned. We also
- // don't currently keep track of bands very well in NoBandChannelHelper.
- return false;
- }
-
- @Override
- public boolean isEmpty() {
- return !mAllChannels && mChannels.isEmpty();
- }
-
- @Override
- public boolean isAllChannels() {
- return mAllChannels;
- }
-
- @Override
- public void clear() {
- mAllChannels = false;
- mChannels.clear();
- }
-
- @Override
- public Set<Integer> getMissingChannelsFromBand(int band) {
- // We don't need to partially collapse settings in wificond scanner because we
- // don't have any limitation on the number of channels that can be scanned. We also
- // don't currently keep track of bands very well in NoBandChannelHelper.
- return new ArraySet<Integer>();
- }
-
- @Override
- public Set<Integer> getContainingChannelsFromBand(int band) {
- // We don't need to partially collapse settings in wificond scanner because we
- // don't have any limitation on the number of channels that can be scanned. We also
- // don't currently keep track of bands very well in NoBandChannelHelper.
- return new ArraySet<Integer>();
- }
-
- @Override
- public Set<Integer> getChannelSet() {
- if (!isEmpty() && !mAllChannels) {
- return mChannels;
- } else {
- return new ArraySet<>();
- }
- }
-
- @Override
- public void fillBucketSettings(WifiNative.BucketSettings bucketSettings, int maxChannels) {
- if (mAllChannels || mChannels.size() > maxChannels) {
- bucketSettings.band = WifiScanner.WIFI_BAND_BOTH_WITH_DFS;
- bucketSettings.num_channels = 0;
- bucketSettings.channels = null;
- } else {
- bucketSettings.band = WifiScanner.WIFI_BAND_UNSPECIFIED;
- bucketSettings.num_channels = mChannels.size();
- bucketSettings.channels = new WifiNative.ChannelSettings[mChannels.size()];
- for (int i = 0; i < mChannels.size(); ++i) {
- WifiNative.ChannelSettings channelSettings = new WifiNative.ChannelSettings();
- channelSettings.frequency = mChannels.valueAt(i);
- bucketSettings.channels[i] = channelSettings;
- }
- }
- }
-
- @Override
- public Set<Integer> getScanFreqs() {
- if (mAllChannels) {
- return null;
- } else {
- return new ArraySet<Integer>(mChannels);
- }
- }
- }
-
- @Override
- public ChannelCollection createChannelCollection() {
- return new NoBandChannelCollection();
- }
-}
diff --git a/service/java/com/android/server/wifi/scanner/WifiScannerImpl.java b/service/java/com/android/server/wifi/scanner/WifiScannerImpl.java
index 5281b3a..75b24d8 100644
--- a/service/java/com/android/server/wifi/scanner/WifiScannerImpl.java
+++ b/service/java/com/android/server/wifi/scanner/WifiScannerImpl.java
@@ -53,8 +53,8 @@
if (wifiNative.getBgScanCapabilities(new WifiNative.ScanCapabilities())) {
return new HalWifiScannerImpl(context, wifiNative, wifiMonitor, looper, clock);
} else {
- return new WificondScannerImpl(context, wifiNative, wifiMonitor, looper,
- clock);
+ return new WificondScannerImpl(context, wifiNative, wifiMonitor,
+ new WificondChannelHelper(wifiNative), looper, clock);
}
}
};
@@ -155,11 +155,5 @@
*/
public abstract boolean isHwPnoSupported(boolean isConnectedPno);
- /**
- * This returns whether a background scan should be running for HW PNO scan or not.
- * @return true if background scan needs to be started, false otherwise.
- */
- public abstract boolean shouldScheduleBackgroundScanForHwPno();
-
protected abstract void dump(FileDescriptor fd, PrintWriter pw, String[] args);
}
diff --git a/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java b/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java
index 4b8e284..ed1bedf 100644
--- a/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java
+++ b/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java
@@ -75,7 +75,6 @@
private static final String TAG = WifiScanningService.TAG;
private static final boolean DBG = false;
- private static final int MIN_PERIOD_PER_CHANNEL_MS = 200; // DFS needs 120 ms
private static final int UNKNOWN_PID = -1;
private final LocalLog mLocalLog = new LocalLog(512);
@@ -240,10 +239,6 @@
private static final int CMD_SCAN_RESULTS_AVAILABLE = BASE + 0;
private static final int CMD_FULL_SCAN_RESULTS = BASE + 1;
- private static final int CMD_HOTLIST_AP_FOUND = BASE + 2;
- private static final int CMD_HOTLIST_AP_LOST = BASE + 3;
- private static final int CMD_WIFI_CHANGE_DETECTED = BASE + 4;
- private static final int CMD_WIFI_CHANGE_TIMEOUT = BASE + 5;
private static final int CMD_DRIVER_LOADED = BASE + 6;
private static final int CMD_DRIVER_UNLOADED = BASE + 7;
private static final int CMD_SCAN_PAUSED = BASE + 8;
@@ -1341,7 +1336,6 @@
* -Started State
* -Hw Pno Scan state
* -Single Scan state
- * -Sw Pno Scan state
*
* These are the main state transitions:
* 1. Start at |Default State|
@@ -1353,11 +1347,6 @@
* contains IE (information elements). If yes, send the results to the client, else
* switch to |Single Scan state| and send the result to the client when the scan result
* is obtained.
- * b.1. Switch to |Sw Pno Scan state| when the device does not supports HW PNO
- * (This is for older devices which do not support HW PNO and for connected PNO on
- * devices which support wificond based PNO)
- * b.2. In |Sw Pno Scan state| send the result to the client when the background scan result
- * is obtained
*
* Note: PNO scans only work for a single client today. We don't have support in HW to support
* multiple requests at the same time, so will need non-trivial changes to support (if at all
@@ -1368,7 +1357,6 @@
private final DefaultState mDefaultState = new DefaultState();
private final StartedState mStartedState = new StartedState();
private final HwPnoScanState mHwPnoScanState = new HwPnoScanState();
- private final SwPnoScanState mSwPnoScanState = new SwPnoScanState();
private final SingleScanState mSingleScanState = new SingleScanState();
private InternalClientInfo mInternalClientInfo;
@@ -1386,7 +1374,6 @@
addState(mStartedState, mDefaultState);
addState(mHwPnoScanState, mStartedState);
addState(mSingleScanState, mHwPnoScanState);
- addState(mSwPnoScanState, mStartedState);
// CHECKSTYLE:ON IndentationCheck
setInitialState(mDefaultState);
@@ -1466,12 +1453,11 @@
pnoParams.setDefusable(true);
PnoSettings pnoSettings =
pnoParams.getParcelable(WifiScanner.PNO_PARAMS_PNO_SETTINGS_KEY);
- // This message is handled after the transition to SwPnoScan/HwPnoScan state
- deferMessage(msg);
if (mScannerImpl.isHwPnoSupported(pnoSettings.isConnected)) {
+ deferMessage(msg);
transitionTo(mHwPnoScanState);
} else {
- transitionTo(mSwPnoScanState);
+ replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "not supported");
}
break;
case WifiScanner.CMD_STOP_PNO_SCAN:
@@ -1582,68 +1568,6 @@
}
}
- class SwPnoScanState extends State {
- private final ArrayList<ScanResult> mSwPnoFullScanResults = new ArrayList<>();
-
- @Override
- public void enter() {
- if (DBG) localLog("SwPnoScanState");
- mSwPnoFullScanResults.clear();
- }
-
- @Override
- public void exit() {
- removeInternalClient();
- }
-
- @Override
- public boolean processMessage(Message msg) {
- ClientInfo ci = mClients.get(msg.replyTo);
- switch (msg.what) {
- case WifiScanner.CMD_START_PNO_SCAN:
- Bundle pnoParams = (Bundle) msg.obj;
- if (pnoParams == null) {
- replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "params null");
- return HANDLED;
- }
- pnoParams.setDefusable(true);
- PnoSettings pnoSettings =
- pnoParams.getParcelable(WifiScanner.PNO_PARAMS_PNO_SETTINGS_KEY);
- ScanSettings scanSettings =
- pnoParams.getParcelable(WifiScanner.PNO_PARAMS_SCAN_SETTINGS_KEY);
- if (addSwPnoScanRequest(ci, msg.arg2, scanSettings, pnoSettings)) {
- replySucceeded(msg);
- } else {
- replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "bad request");
- transitionTo(mStartedState);
- }
- break;
- case WifiScanner.CMD_STOP_PNO_SCAN:
- removeSwPnoScanRequest(ci, msg.arg2);
- transitionTo(mStartedState);
- break;
- case WifiScanner.CMD_FULL_SCAN_RESULT:
- // Aggregate full scan results until we get the |CMD_SCAN_RESULT| message
- mSwPnoFullScanResults.add((ScanResult) msg.obj);
- break;
- case WifiScanner.CMD_SCAN_RESULT:
- ScanResult[] scanResults = mSwPnoFullScanResults.toArray(
- new ScanResult[mSwPnoFullScanResults.size()]);
- reportPnoNetworkFound(scanResults);
- mSwPnoFullScanResults.clear();
- break;
- case WifiScanner.CMD_OP_FAILED:
- sendPnoScanFailedToAllAndClear(
- WifiScanner.REASON_UNSPECIFIED, "background scan failed");
- transitionTo(mStartedState);
- break;
- default:
- return NOT_HANDLED;
- }
- return HANDLED;
- }
- }
-
private WifiNative.PnoSettings convertSettingsToPnoNative(ScanSettings scanSettings,
PnoSettings pnoSettings) {
WifiNative.PnoSettings nativePnoSetting = new WifiNative.PnoSettings();
@@ -1724,10 +1648,7 @@
}
logScanRequest("addHwPnoScanRequest", ci, handler, null, scanSettings, pnoSettings);
addPnoScanRequest(ci, handler, scanSettings, pnoSettings);
- // HW PNO is supported, check if we need a background scan running for this.
- if (mScannerImpl.shouldScheduleBackgroundScanForHwPno()) {
- addBackgroundScanRequest(scanSettings);
- }
+
return true;
}
@@ -1739,34 +1660,6 @@
}
}
- private boolean addSwPnoScanRequest(ClientInfo ci, int handler, ScanSettings scanSettings,
- PnoSettings pnoSettings) {
- if (ci == null) {
- Log.d(TAG, "Failing scan request ClientInfo not found " + handler);
- return false;
- }
- if (!mActivePnoScans.isEmpty()) {
- loge("Failing scan request because there is already an active scan");
- return false;
- }
- logScanRequest("addSwPnoScanRequest", ci, handler, null, scanSettings, pnoSettings);
- addPnoScanRequest(ci, handler, scanSettings, pnoSettings);
- // HW PNO is not supported, we need to revert to normal background scans and
- // report events after each scan and we need full scan results to get the IE information
- scanSettings.reportEvents = WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN
- | WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT;
- addBackgroundScanRequest(scanSettings);
- return true;
- }
-
- private void removeSwPnoScanRequest(ClientInfo ci, int handler) {
- if (ci != null) {
- Pair<PnoSettings, ScanSettings> settings = removePnoScanRequest(ci, handler);
- logScanRequest("removeSwPnoScanRequest", ci, handler, null,
- settings.second, settings.first);
- }
- }
-
private void reportPnoNetworkFound(ScanResult[] results) {
WifiScanner.ParcelableScanResults parcelableScanResults =
new WifiScanner.ParcelableScanResults(results);
@@ -1789,15 +1682,6 @@
mActivePnoScans.clear();
}
- private void addBackgroundScanRequest(ScanSettings settings) {
- if (DBG) localLog("Starting background scan");
- if (mInternalClientInfo != null) {
- mInternalClientInfo.sendRequestToClientHandler(
- WifiScanner.CMD_START_BACKGROUND_SCAN, settings,
- WifiStateMachine.WIFI_WORK_SOURCE);
- }
- }
-
private void addSingleScanRequest(ScanSettings settings) {
if (DBG) localLog("Starting single scan");
if (mInternalClientInfo != null) {
@@ -2213,7 +2097,7 @@
static String describeTo(StringBuilder sb, ScanSettings scanSettings) {
sb.append("ScanSettings { ")
- .append(" band:").append(scanSettings.band)
+ .append(" band:").append(ChannelHelper.bandToString(scanSettings.band))
.append(" period:").append(scanSettings.periodInMs)
.append(" reportEvents:").append(scanSettings.reportEvents)
.append(" numBssidsPerScan:").append(scanSettings.numBssidsPerScan)
diff --git a/service/java/com/android/server/wifi/scanner/HalChannelHelper.java b/service/java/com/android/server/wifi/scanner/WificondChannelHelper.java
similarity index 79%
rename from service/java/com/android/server/wifi/scanner/HalChannelHelper.java
rename to service/java/com/android/server/wifi/scanner/WificondChannelHelper.java
index e8b646d..7cfeb72 100644
--- a/service/java/com/android/server/wifi/scanner/HalChannelHelper.java
+++ b/service/java/com/android/server/wifi/scanner/WificondChannelHelper.java
@@ -22,15 +22,15 @@
import com.android.server.wifi.WifiNative;
/**
- * KnownBandsChannelHelper that uses band to channel mappings retrieved from the HAL.
- * Also supporting updating the channel list from the HAL on demand.
+ * KnownBandsChannelHelper that uses band to channel mappings retrieved from wificond.
+ * Also supporting updating the channel list from the wificond on demand.
*/
-public class HalChannelHelper extends KnownBandsChannelHelper {
- private static final String TAG = "HalChannelHelper";
+public class WificondChannelHelper extends KnownBandsChannelHelper {
+ private static final String TAG = "WificondChannelHelper";
private final WifiNative mWifiNative;
- public HalChannelHelper(WifiNative wifiNative) {
+ public WificondChannelHelper(WifiNative wifiNative) {
mWifiNative = wifiNative;
final int[] emptyFreqList = new int[0];
setBandChannels(emptyFreqList, emptyFreqList, emptyFreqList);
@@ -39,11 +39,13 @@
@Override
public void updateChannels() {
- int[] channels24G = mWifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_24_GHZ);
+ int[] channels24G =
+ mWifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_24_GHZ);
if (channels24G == null) Log.e(TAG, "Failed to get channels for 2.4GHz band");
int[] channels5G = mWifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ);
if (channels5G == null) Log.e(TAG, "Failed to get channels for 5GHz band");
- int[] channelsDfs = mWifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY);
+ int[] channelsDfs =
+ mWifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY);
if (channelsDfs == null) Log.e(TAG, "Failed to get channels for 5GHz DFS only band");
if (channels24G == null || channels5G == null || channelsDfs == null) {
Log.e(TAG, "Failed to get all channels for band, not updating band channel lists");
diff --git a/service/java/com/android/server/wifi/scanner/WificondScannerImpl.java b/service/java/com/android/server/wifi/scanner/WificondScannerImpl.java
index ed25e0f..72a7a27 100644
--- a/service/java/com/android/server/wifi/scanner/WificondScannerImpl.java
+++ b/service/java/com/android/server/wifi/scanner/WificondScannerImpl.java
@@ -34,7 +34,6 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -50,7 +49,6 @@
private static final String TAG = "WificondScannerImpl";
private static final boolean DBG = false;
- public static final String BACKGROUND_PERIOD_ALARM_TAG = TAG + " Background Scan Period";
public static final String TIMEOUT_ALARM_TAG = TAG + " Scan Timeout";
// Max number of networks that can be specified to wificond per scan request
public static final int MAX_HIDDEN_NETWORK_IDS_PER_SCAN = 16;
@@ -69,20 +67,9 @@
private final Object mSettingsLock = new Object();
// Next scan settings to apply when the previous scan completes
- private WifiNative.ScanSettings mPendingBackgroundScanSettings = null;
- private WifiNative.ScanEventHandler mPendingBackgroundScanEventHandler = null;
private WifiNative.ScanSettings mPendingSingleScanSettings = null;
private WifiNative.ScanEventHandler mPendingSingleScanEventHandler = null;
- // Active background scan settings/state
- private WifiNative.ScanSettings mBackgroundScanSettings = null;
- private WifiNative.ScanEventHandler mBackgroundScanEventHandler = null;
- private int mNextBackgroundScanPeriod = 0;
- private int mNextBackgroundScanId = 0;
- private boolean mBackgroundScanPeriodPending = false;
- private boolean mBackgroundScanPaused = false;
- private ScanBuffer mBackgroundScanBuffer = new ScanBuffer(SCAN_BUFFER_CAPACITY);
-
private ArrayList<ScanDetail> mNativeScanResults;
private WifiScanner.ScanData mLatestSingleScanResult =
new WifiScanner.ScanData(0, 0, new ScanResult[0]);
@@ -110,14 +97,6 @@
*/
private static final long SCAN_TIMEOUT_MS = 15000;
- AlarmManager.OnAlarmListener mScanPeriodListener = new AlarmManager.OnAlarmListener() {
- public void onAlarm() {
- synchronized (mSettingsLock) {
- handleScanPeriod();
- }
- }
- };
-
AlarmManager.OnAlarmListener mScanTimeoutListener = new AlarmManager.OnAlarmListener() {
public void onAlarm() {
synchronized (mSettingsLock) {
@@ -149,19 +128,12 @@
WifiMonitor.SCAN_RESULTS_EVENT, mEventHandler);
}
- public WificondScannerImpl(Context context, WifiNative wifiNative,
- WifiMonitor wifiMonitor, Looper looper, Clock clock) {
- // TODO get channel information from wificond.
- this(context, wifiNative, wifiMonitor, new NoBandChannelHelper(), looper, clock);
- }
-
@Override
public void cleanup() {
synchronized (mSettingsLock) {
mPendingSingleScanSettings = null;
mPendingSingleScanEventHandler = null;
stopHwPnoScan();
- stopBatchedScan();
mLastScanSettings = null; // finally clear any active scan
}
}
@@ -189,12 +161,12 @@
+ ",eventHandler=" + eventHandler);
return false;
}
- if (mPendingSingleScanSettings != null
- || (mLastScanSettings != null && mLastScanSettings.singleScanActive)) {
- Log.w(TAG, "A single scan is already running");
- return false;
- }
synchronized (mSettingsLock) {
+ if (mPendingSingleScanSettings != null
+ || (mLastScanSettings != null && mLastScanSettings.singleScanActive)) {
+ Log.w(TAG, "A single scan is already running");
+ return false;
+ }
mPendingSingleScanSettings = settings;
mPendingSingleScanEventHandler = eventHandler;
processPendingScans();
@@ -210,111 +182,23 @@
@Override
public boolean startBatchedScan(WifiNative.ScanSettings settings,
WifiNative.ScanEventHandler eventHandler) {
- if (settings == null || eventHandler == null) {
- Log.w(TAG, "Invalid arguments for startBatched: settings=" + settings
- + ",eventHandler=" + eventHandler);
- return false;
- }
-
- if (settings.max_ap_per_scan < 0 || settings.max_ap_per_scan > MAX_APS_PER_SCAN) {
- return false;
- }
- if (settings.num_buckets < 0 || settings.num_buckets > MAX_SCAN_BUCKETS) {
- return false;
- }
- if (settings.report_threshold_num_scans < 0
- || settings.report_threshold_num_scans > SCAN_BUFFER_CAPACITY) {
- return false;
- }
- if (settings.report_threshold_percent < 0 || settings.report_threshold_percent > 100) {
- return false;
- }
- if (settings.base_period_ms <= 0) {
- return false;
- }
- for (int i = 0; i < settings.num_buckets; ++i) {
- WifiNative.BucketSettings bucket = settings.buckets[i];
- if (bucket.period_ms % settings.base_period_ms != 0) {
- return false;
- }
- }
-
- synchronized (mSettingsLock) {
- stopBatchedScan();
- if (DBG) {
- Log.d(TAG, "Starting scan num_buckets=" + settings.num_buckets + ", base_period="
- + settings.base_period_ms + " ms");
- }
- mPendingBackgroundScanSettings = settings;
- mPendingBackgroundScanEventHandler = eventHandler;
- handleScanPeriod(); // Try to start scan immediately
- return true;
- }
+ Log.w(TAG, "startBatchedScan() is not supported");
+ return false;
}
@Override
public void stopBatchedScan() {
- synchronized (mSettingsLock) {
- if (DBG) Log.d(TAG, "Stopping scan");
- mBackgroundScanSettings = null;
- mBackgroundScanEventHandler = null;
- mPendingBackgroundScanSettings = null;
- mPendingBackgroundScanEventHandler = null;
- mBackgroundScanPaused = false;
- mBackgroundScanPeriodPending = false;
- unscheduleScansLocked();
- }
- processPendingScans();
+ Log.w(TAG, "stopBatchedScan() is not supported");
}
@Override
public void pauseBatchedScan() {
- synchronized (mSettingsLock) {
- if (DBG) Log.d(TAG, "Pausing scan");
- // if there isn't a pending scan then make the current scan pending
- if (mPendingBackgroundScanSettings == null) {
- mPendingBackgroundScanSettings = mBackgroundScanSettings;
- mPendingBackgroundScanEventHandler = mBackgroundScanEventHandler;
- }
- mBackgroundScanSettings = null;
- mBackgroundScanEventHandler = null;
- mBackgroundScanPeriodPending = false;
- mBackgroundScanPaused = true;
-
- unscheduleScansLocked();
-
- WifiScanner.ScanData[] results = getLatestBatchedScanResults(/* flush = */ true);
- if (mPendingBackgroundScanEventHandler != null) {
- mPendingBackgroundScanEventHandler.onScanPaused(results);
- }
- }
- processPendingScans();
+ Log.w(TAG, "pauseBatchedScan() is not supported");
}
@Override
public void restartBatchedScan() {
- synchronized (mSettingsLock) {
- if (DBG) Log.d(TAG, "Restarting scan");
- if (mPendingBackgroundScanEventHandler != null) {
- mPendingBackgroundScanEventHandler.onScanRestarted();
- }
- mBackgroundScanPaused = false;
- handleScanPeriod();
- }
- }
-
- private void unscheduleScansLocked() {
- mAlarmManager.cancel(mScanPeriodListener);
- if (mLastScanSettings != null) {
- mLastScanSettings.backgroundScanActive = false;
- }
- }
-
- private void handleScanPeriod() {
- synchronized (mSettingsLock) {
- mBackgroundScanPeriodPending = true;
- processPendingScans();
- }
+ Log.w(TAG, "restartBatchedScan() is not supported");
}
private void handleScanTimeout() {
@@ -342,56 +226,6 @@
final LastScanSettings newScanSettings =
new LastScanSettings(mClock.getElapsedSinceBootMillis());
- // Update scan settings if there is a pending scan
- if (!mBackgroundScanPaused) {
- if (mPendingBackgroundScanSettings != null) {
- mBackgroundScanSettings = mPendingBackgroundScanSettings;
- mBackgroundScanEventHandler = mPendingBackgroundScanEventHandler;
- mNextBackgroundScanPeriod = 0;
- mPendingBackgroundScanSettings = null;
- mPendingBackgroundScanEventHandler = null;
- mBackgroundScanPeriodPending = true;
- }
- if (mBackgroundScanPeriodPending && mBackgroundScanSettings != null) {
- int reportEvents = WifiScanner.REPORT_EVENT_NO_BATCH; // default to no batch
- for (int bucket_id = 0; bucket_id < mBackgroundScanSettings.num_buckets;
- ++bucket_id) {
- WifiNative.BucketSettings bucket =
- mBackgroundScanSettings.buckets[bucket_id];
- if (mNextBackgroundScanPeriod % (bucket.period_ms
- / mBackgroundScanSettings.base_period_ms) == 0) {
- if ((bucket.report_events
- & WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN) != 0) {
- reportEvents |= WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN;
- }
- if ((bucket.report_events
- & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) != 0) {
- reportEvents |= WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT;
- }
- // only no batch if all buckets specify it
- if ((bucket.report_events
- & WifiScanner.REPORT_EVENT_NO_BATCH) == 0) {
- reportEvents &= ~WifiScanner.REPORT_EVENT_NO_BATCH;
- }
-
- allFreqs.addChannels(bucket);
- }
- }
- if (!allFreqs.isEmpty()) {
- newScanSettings.setBackgroundScan(mNextBackgroundScanId++,
- mBackgroundScanSettings.max_ap_per_scan, reportEvents,
- mBackgroundScanSettings.report_threshold_num_scans,
- mBackgroundScanSettings.report_threshold_percent);
- }
- mNextBackgroundScanPeriod++;
- mBackgroundScanPeriodPending = false;
- mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
- mClock.getElapsedSinceBootMillis()
- + mBackgroundScanSettings.base_period_ms,
- BACKGROUND_PERIOD_ALARM_TAG, mScanPeriodListener, mEventHandler);
- }
- }
-
if (mPendingSingleScanSettings != null) {
boolean reportFullResults = false;
ChannelCollection singleScanFreqs = mChannelHelper.createChannelCollection();
@@ -422,7 +256,7 @@
mPendingSingleScanEventHandler = null;
}
- if (newScanSettings.backgroundScanActive || newScanSettings.singleScanActive) {
+ if (newScanSettings.singleScanActive) {
boolean success = false;
Set<Integer> freqs;
if (!allFreqs.isEmpty()) {
@@ -442,7 +276,6 @@
// TODO handle scan timeout
if (DBG) {
Log.d(TAG, "Starting wifi scan for freqs=" + freqs
- + ", background=" + newScanSettings.backgroundScanActive
+ ", single=" + newScanSettings.singleScanActive);
}
mLastScanSettings = newScanSettings;
@@ -459,7 +292,6 @@
}
}
});
- // TODO(b/27769665) background scans should be failed too if scans fail enough
}
} else if (isHwPnoScanRequired()) {
newScanSettings.setHwPnoScan(mPnoSettings.networkList, mPnoEventHandler);
@@ -522,7 +354,6 @@
mLastScanSettings.singleScanEventHandler
.onScanStatus(WifiNative.WIFI_SCAN_FAILED);
}
- // TODO(b/27769665) background scans should be failed too if scans fail enough
mLastScanSettings = null;
}
}
@@ -607,18 +438,13 @@
return;
}
- if (DBG) Log.d(TAG, "Polling scan data for scan: " + mLastScanSettings.scanId);
mNativeScanResults = mWifiNative.getScanResults();
List<ScanResult> singleScanResults = new ArrayList<>();
- List<ScanResult> backgroundScanResults = new ArrayList<>();
int numFilteredScanResults = 0;
for (int i = 0; i < mNativeScanResults.size(); ++i) {
ScanResult result = mNativeScanResults.get(i).getScanResult();
long timestamp_ms = result.timestamp / 1000; // convert us -> ms
if (timestamp_ms > mLastScanSettings.startTime) {
- if (mLastScanSettings.backgroundScanActive) {
- backgroundScanResults.add(result);
- }
if (mLastScanSettings.singleScanActive
&& mLastScanSettings.singleScanFreqs.containsChannel(
result.frequency)) {
@@ -632,49 +458,6 @@
Log.d(TAG, "Filtering out " + numFilteredScanResults + " scan results.");
}
- if (mLastScanSettings.backgroundScanActive) {
- if (mBackgroundScanEventHandler != null) {
- if ((mLastScanSettings.reportEvents
- & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) != 0) {
- for (ScanResult scanResult : backgroundScanResults) {
- // TODO(b/27506257): Fill in correct bucketsScanned value
- mBackgroundScanEventHandler.onFullScanResult(scanResult, 0);
- }
- }
- }
-
- Collections.sort(backgroundScanResults, SCAN_RESULT_SORT_COMPARATOR);
- ScanResult[] scanResultsArray = new ScanResult[Math.min(mLastScanSettings.maxAps,
- backgroundScanResults.size())];
- for (int i = 0; i < scanResultsArray.length; ++i) {
- scanResultsArray[i] = backgroundScanResults.get(i);
- }
-
- if ((mLastScanSettings.reportEvents & WifiScanner.REPORT_EVENT_NO_BATCH) == 0) {
- // TODO(b/27506257): Fill in correct bucketsScanned value
- mBackgroundScanBuffer.add(new WifiScanner.ScanData(mLastScanSettings.scanId, 0,
- scanResultsArray));
- }
-
- if (mBackgroundScanEventHandler != null) {
- if ((mLastScanSettings.reportEvents
- & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) != 0
- || (mLastScanSettings.reportEvents
- & WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN) != 0
- || (mLastScanSettings.reportEvents
- == WifiScanner.REPORT_EVENT_AFTER_BUFFER_FULL
- && (mBackgroundScanBuffer.size()
- >= (mBackgroundScanBuffer.capacity()
- * mLastScanSettings.reportPercentThreshold
- / 100)
- || mBackgroundScanBuffer.size()
- >= mLastScanSettings.reportNumScansThreshold))) {
- mBackgroundScanEventHandler
- .onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
- }
- }
- }
-
if (mLastScanSettings.singleScanActive
&& mLastScanSettings.singleScanEventHandler != null) {
if (mLastScanSettings.reportSingleScanFullResults) {
@@ -685,7 +468,7 @@
}
}
Collections.sort(singleScanResults, SCAN_RESULT_SORT_COMPARATOR);
- mLatestSingleScanResult = new WifiScanner.ScanData(mLastScanSettings.scanId, 0, 0,
+ mLatestSingleScanResult = new WifiScanner.ScanData(0, 0, 0,
isAllChannelsScanned(mLastScanSettings.singleScanFreqs),
singleScanResults.toArray(new ScanResult[singleScanResults.size()]));
mLastScanSettings.singleScanEventHandler
@@ -699,13 +482,7 @@
@Override
public WifiScanner.ScanData[] getLatestBatchedScanResults(boolean flush) {
- synchronized (mSettingsLock) {
- WifiScanner.ScanData[] results = mBackgroundScanBuffer.get();
- if (flush) {
- mBackgroundScanBuffer.clear();
- }
- return results;
- }
+ return null;
}
private boolean startHwPnoScan(WifiNative.PnoSettings pnoSettings) {
@@ -735,8 +512,10 @@
}
private boolean isHwPnoScanRequired() {
- if (mPnoSettings == null) return false;
- return isHwPnoScanRequired(mPnoSettings.isConnected);
+ synchronized (mSettingsLock) {
+ if (mPnoSettings == null) return false;
+ return isHwPnoScanRequired(mPnoSettings.isConnected);
+ }
}
@Override
@@ -778,11 +557,6 @@
}
@Override
- public boolean shouldScheduleBackgroundScanForHwPno() {
- return false;
- }
-
- @Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
synchronized (mSettingsLock) {
pw.println("Latest native scan results:");
@@ -823,24 +597,6 @@
this.startTime = startTime;
}
- // Background settings
- public boolean backgroundScanActive = false;
- public int scanId;
- public int maxAps;
- public int reportEvents;
- public int reportNumScansThreshold;
- public int reportPercentThreshold;
-
- public void setBackgroundScan(int scanId, int maxAps, int reportEvents,
- int reportNumScansThreshold, int reportPercentThreshold) {
- this.backgroundScanActive = true;
- this.scanId = scanId;
- this.maxAps = maxAps;
- this.reportEvents = reportEvents;
- this.reportNumScansThreshold = reportNumScansThreshold;
- this.reportPercentThreshold = reportPercentThreshold;
- }
-
// Single scan settings
public boolean singleScanActive = false;
public boolean reportSingleScanFullResults;
@@ -869,44 +625,6 @@
}
}
-
- private static class ScanBuffer {
- private final ArrayDeque<WifiScanner.ScanData> mBuffer;
- private int mCapacity;
-
- ScanBuffer(int capacity) {
- mCapacity = capacity;
- mBuffer = new ArrayDeque<>(mCapacity);
- }
-
- public int size() {
- return mBuffer.size();
- }
-
- public int capacity() {
- return mCapacity;
- }
-
- public boolean isFull() {
- return size() == mCapacity;
- }
-
- public void add(WifiScanner.ScanData scanData) {
- if (isFull()) {
- mBuffer.pollFirst();
- }
- mBuffer.offerLast(scanData);
- }
-
- public void clear() {
- mBuffer.clear();
- }
-
- public WifiScanner.ScanData[] get() {
- return mBuffer.toArray(new WifiScanner.ScanData[mBuffer.size()]);
- }
- }
-
/**
* HW PNO Debouncer is used to debounce PNO requests. This guards against toggling the PNO
* state too often which is not handled very well by some drivers.
diff --git a/service/java/com/android/server/wifi/util/ApConfigUtil.java b/service/java/com/android/server/wifi/util/ApConfigUtil.java
index 7bbbc03..b1a4948 100644
--- a/service/java/com/android/server/wifi/util/ApConfigUtil.java
+++ b/service/java/com/android/server/wifi/util/ApConfigUtil.java
@@ -133,15 +133,9 @@
config.apBand, allowed2GChannels,
wifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ));
if (config.apChannel == -1) {
- if (wifiNative.isGetChannelsForBandSupported()) {
- /* We're not able to get channel when it is supported by HAL. */
- Log.e(TAG, "Failed to get available channel.");
- return ERROR_NO_CHANNEL;
- }
-
- /* Use the default for HAL without get channel support. */
- config.apBand = DEFAULT_AP_BAND;
- config.apChannel = DEFAULT_AP_CHANNEL;
+ /* We're not able to get channel from wificond. */
+ Log.e(TAG, "Failed to get available channel.");
+ return ERROR_NO_CHANNEL;
}
}
diff --git a/service/java/com/android/server/wifi/util/InformationElementUtil.java b/service/java/com/android/server/wifi/util/InformationElementUtil.java
index c8f9ca3..14912b5 100644
--- a/service/java/com/android/server/wifi/util/InformationElementUtil.java
+++ b/service/java/com/android/server/wifi/util/InformationElementUtil.java
@@ -247,6 +247,10 @@
"Bad Interworking element length: " + ie.bytes.length);
}
+ if (ie.bytes.length == 3 || ie.bytes.length == 9) {
+ int venueInfo = (int) ByteBufferReader.readInteger(data, ByteOrder.BIG_ENDIAN, 2);
+ }
+
if (ie.bytes.length == 7 || ie.bytes.length == 9) {
hessid = ByteBufferReader.readInteger(data, ByteOrder.BIG_ENDIAN, 6);
}
diff --git a/service/java/com/android/server/wifi/util/KalmanFilter.java b/service/java/com/android/server/wifi/util/KalmanFilter.java
new file mode 100644
index 0000000..b961ed8
--- /dev/null
+++ b/service/java/com/android/server/wifi/util/KalmanFilter.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wifi.util;
+
+/**
+ * Utility providiing a basic Kalman filter
+ *
+ * For background, see https://en.wikipedia.org/wiki/Kalman_filter
+ */
+public class KalmanFilter {
+ public Matrix mF; // stateTransition
+ public Matrix mQ; // processNoiseCovariance
+ public Matrix mH; // observationModel
+ public Matrix mR; // observationNoiseCovariance
+ public Matrix mP; // aPosterioriErrorCovariance
+ public Matrix mx; // stateEstimate
+
+ /**
+ * Performs the prediction phase of the filter, using the state estimate to produce
+ * a new estimate for the current timestep.
+ */
+ public void predict() {
+ mx = mF.dot(mx);
+ mP = mF.dot(mP).dotTranspose(mF).plus(mQ);
+ }
+
+ /**
+ * Updates the state estimate to incorporate the new observation z.
+ */
+ public void update(Matrix z) {
+ Matrix y = z.minus(mH.dot(mx));
+ Matrix tS = mH.dot(mP).dotTranspose(mH).plus(mR);
+ Matrix tK = mP.dotTranspose(mH).dot(tS.inverse());
+ mx = mx.plus(tK.dot(y));
+ mP = mP.minus(tK.dot(mH).dot(mP));
+ }
+
+ @Override
+ public String toString() {
+ return "{F: " + mF
+ + " Q: " + mQ
+ + " H: " + mH
+ + " R: " + mR
+ + " P: " + mP
+ + " x: " + mx
+ + "}";
+ }
+}
diff --git a/service/java/com/android/server/wifi/util/Matrix.java b/service/java/com/android/server/wifi/util/Matrix.java
index bdf147e..afd9de6 100644
--- a/service/java/com/android/server/wifi/util/Matrix.java
+++ b/service/java/com/android/server/wifi/util/Matrix.java
@@ -152,6 +152,34 @@
}
/**
+ * Forms a scalar product
+ *
+ * @param scalar is the value to multiply by
+ * @return newly allocated matrix representing the product this and scalar
+ */
+ public Matrix times(double scalar) {
+ return times(scalar, new Matrix(n, m));
+ }
+
+ /**
+ * Forms a scalar product
+ *
+ * @param scalar is the value to multiply by
+ * @param result is space to hold the result
+ * @return result, filled with the matrix difference
+ * @throws IllegalArgumentException if shapes differ
+ */
+ public Matrix times(double scalar, Matrix result) {
+ if (!(this.n == result.n && this.m == result.m)) {
+ throw new IllegalArgumentException();
+ }
+ for (int i = 0; i < mem.length; i++) {
+ result.mem[i] = this.mem[i] * scalar;
+ }
+ return result;
+ }
+
+ /**
* Forms the matrix product of two matrices, this and that
*
* @param that is the other matrix
@@ -291,6 +319,42 @@
}
return result;
}
+ /**
+ * Forms the matrix product with the transpose of a second matrix
+ *
+ * @param that is the other matrix
+ * @return newly allocated matrix representing the matrix product of this and that.transpose()
+ * @throws IllegalArgumentException if shapes are not conformant
+ */
+ public Matrix dotTranspose(Matrix that) {
+ return dotTranspose(that, new Matrix(this.n, that.n));
+ }
+
+ /**
+ * Forms the matrix product with the transpose of a second matrix
+ * <p>
+ * Caller supplies an object to contain the result, as well as scratch space
+ *
+ * @param that is the other matrix
+ * @param result is space to hold the result
+ * @return result, filled with the matrix product of this and that.transpose()
+ * @throws IllegalArgumentException if shapes are not conformant
+ */
+ public Matrix dotTranspose(Matrix that, Matrix result) {
+ if (!(this.n == result.n && this.m == that.m && that.n == result.m)) {
+ throw new IllegalArgumentException();
+ }
+ for (int i = 0; i < n; i++) {
+ for (int j = 0; j < that.n; j++) {
+ double s = 0.0;
+ for (int k = 0; k < m; k++) {
+ s += this.get(i, k) * that.get(j, k);
+ }
+ result.put(i, j, s);
+ }
+ }
+ return result;
+ }
/**
* Tests for equality
diff --git a/service/java/com/android/server/wifi/util/WifiPermissionsUtil.java b/service/java/com/android/server/wifi/util/WifiPermissionsUtil.java
index 52c9618..d3c072f 100644
--- a/service/java/com/android/server/wifi/util/WifiPermissionsUtil.java
+++ b/service/java/com/android/server/wifi/util/WifiPermissionsUtil.java
@@ -17,23 +17,16 @@
package com.android.server.wifi.util;
import android.Manifest;
-import android.annotation.Nullable;
import android.app.AppOpsManager;
-import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
-import android.net.ConnectivityManager;
import android.net.NetworkScoreManager;
-import android.net.NetworkScorerAppData;
-import android.net.wifi.WifiConfiguration;
import android.os.Binder;
import android.os.RemoteException;
import android.os.UserManager;
import android.provider.Settings;
-import android.text.TextUtils;
-import com.android.server.wifi.FrameworkFacade;
import com.android.server.wifi.WifiInjector;
import com.android.server.wifi.WifiLog;
import com.android.server.wifi.WifiSettingsStore;
@@ -52,7 +45,6 @@
private final UserManager mUserManager;
private final WifiSettingsStore mSettingsStore;
private final NetworkScoreManager mNetworkScoreManager;
- private final FrameworkFacade mFrameworkFacade;
private WifiLog mLog;
public WifiPermissionsUtil(WifiPermissionsWrapper wifiPermissionsWrapper,
@@ -65,7 +57,6 @@
mSettingsStore = settingsStore;
mLog = wifiInjector.makeLog(TAG);
mNetworkScoreManager = networkScoreManager;
- mFrameworkFacade = wifiInjector.getFrameworkFacade();
}
/**
@@ -101,16 +92,6 @@
}
/**
- * Check and enforce tether change permission.
- *
- * @param context Context object of the caller.
- */
- public void enforceTetherChangePermission(Context context) {
- String pkgName = context.getOpPackageName();
- ConnectivityManager.enforceTetherChangePermission(context, pkgName);
- }
-
- /**
* Check and enforce Location permission.
*
* @param pkgName PackageName of the application requesting access
@@ -176,79 +157,8 @@
}
// If the User or profile is current, permission is granted
// Otherwise, uid must have INTERACT_ACROSS_USERS_FULL permission.
- if (!canAccessUserProfile(uid)) {
- mLog.tC("Denied: Profile not permitted");
- return false;
- }
- return true;
- }
-
- /**
- * API to determine if the caller has permissions to get a {@link android.net.wifi.WifiInfo}
- * instance containing the SSID and BSSID.
- *
- *
- * @param currentConfig the currently connected WiFi config
- * @param pkgName package name of the application requesting access
- * @param uid The uid of the package
- * @param minVersion Minimum app API Version number to enforce location permission
- * @return boolean true if the SSID/BSSID can be sent to the user, false if they
- * should be hidden/removed.
- */
- public boolean canAccessFullConnectionInfo(@Nullable WifiConfiguration currentConfig,
- String pkgName, int uid, int minVersion) throws SecurityException {
- mAppOps.checkPackage(uid, pkgName);
-
- // The User or profile must be current or the uid must
- // have INTERACT_ACROSS_USERS_FULL permission.
- if (!canAccessUserProfile(uid)) {
- mLog.tC("Denied: Profile not permitted");
- return false;
- }
-
- // If the caller has scan result access then they can also see the full connection info.
- // Otherwise the caller must be the active use open wifi package and the current config
- // must be for an open network.
- return canAccessScanResults(pkgName, uid, minVersion)
- || isUseOpenWifiPackageWithConnectionInfoAccess(currentConfig, pkgName);
-
- }
-
- /**
- * Returns true if the given WiFi config is for an open network and the package is the active
- * use open wifi app.
- */
- private boolean isUseOpenWifiPackageWithConnectionInfoAccess(
- @Nullable WifiConfiguration currentConfig, String pkgName) {
-
- // Access is only granted for open networks.
- if (currentConfig == null) {
- mLog.tC("Denied: WifiConfiguration is NULL.");
- return false;
- }
-
- // Access is only granted for open networks.
- if (!currentConfig.isOpenNetwork()) {
- mLog.tC("Denied: The current config is not for an open network.");
- return false;
- }
-
- // The USE_OPEN_WIFI_PACKAGE can access the full connection info details without
- // scan result access.
- if (!isUseOpenWifiPackage(pkgName)) {
- mLog.tC("Denied: caller is not the current USE_OPEN_WIFI_PACKAGE");
- return false;
- }
-
- return true;
- }
-
- /**
- * Returns true if the User or profile is current or the
- * uid has the INTERACT_ACROSS_USERS_FULL permission.
- */
- private boolean canAccessUserProfile(int uid) {
if (!isCurrentProfile(uid) && !checkInteractAcrossUsersFull(uid)) {
+ mLog.tC("Denied: Profile not permitted");
return false;
}
return true;
@@ -271,43 +181,6 @@
}
/**
- * Returns true if the given package is equal to the setting keyed by
- * {@link Settings.Global#USE_OPEN_WIFI_PACKAGE} and the NetworkScoreManager
- * has the package name set as the use open wifi package.
- */
- private boolean isUseOpenWifiPackage(String packageName) {
- if (TextUtils.isEmpty(packageName)) {
- return false;
- }
-
- // When the setting is enabled it's set to the package name of the use open wifi app.
- final String useOpenWifiPkg =
- mFrameworkFacade.getStringSetting(mContext, Settings.Global.USE_OPEN_WIFI_PACKAGE);
- if (packageName.equals(useOpenWifiPkg)) {
- // If the package name matches the setting then also confirm that the scorer is
- // active and the package matches the expected use open wifi package from the scorer's
- // perspective. The scorer can be active when the use open wifi feature is off so we
- // can't rely on this check alone.
- // TODO(b/67278755): Refactor this into an API similar to isCallerActiveScorer()
- final NetworkScorerAppData appData;
- final long token = Binder.clearCallingIdentity();
- try {
- appData = mNetworkScoreManager.getActiveScorer();
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- if (appData != null) {
- final ComponentName enableUseOpenWifiActivity =
- appData.getEnableUseOpenWifiActivity();
- return enableUseOpenWifiActivity != null
- && packageName.equals(enableUseOpenWifiActivity.getPackageName());
- }
- }
-
- return false;
- }
-
- /**
* Returns true if Wifi scan operation is allowed for this caller
* and package.
*/
diff --git a/tests/wifitests/Android.mk b/tests/wifitests/Android.mk
index 1e64ddb..11e508d 100644
--- a/tests/wifitests/Android.mk
+++ b/tests/wifitests/Android.mk
@@ -105,6 +105,7 @@
libwifi-system \
libui \
libunwind \
+ libunwindstack \
libutils \
libvndksupport \
diff --git a/tests/wifitests/AndroidTest.xml b/tests/wifitests/AndroidTest.xml
index 4fe21aa..61a9233 100644
--- a/tests/wifitests/AndroidTest.xml
+++ b/tests/wifitests/AndroidTest.xml
@@ -22,6 +22,6 @@
<option name="test-tag" value="FrameworksWifiTests" />
<test class="com.android.tradefed.testtype.InstrumentationTest" >
<option name="package" value="com.android.server.wifi.test" />
- <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
+ <option name="runner" value="com.android.server.wifi.CustomTestRunner" />
</test>
</configuration>
diff --git a/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java b/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java
index 7a25e17..18a1f8f 100644
--- a/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java
@@ -17,6 +17,7 @@
package com.android.server.wifi;
import static com.android.server.wifi.HalDeviceManager.START_HAL_RETRY_TIMES;
+import static com.android.server.wifi.HalDeviceManager.getName;
import static junit.framework.Assert.assertEquals;
@@ -51,10 +52,13 @@
import android.hardware.wifi.V1_0.WifiStatusCode;
import android.hidl.manager.V1_0.IServiceManager;
import android.hidl.manager.V1_0.IServiceNotification;
+import android.os.Handler;
import android.os.IHwBinder;
import android.os.test.TestLooper;
import android.util.Log;
+import com.android.server.wifi.HalDeviceManager.InterfaceDestroyedListener;
+
import org.hamcrest.core.IsNull;
import org.junit.After;
import org.junit.Before;
@@ -82,7 +86,9 @@
@Mock IServiceManager mServiceManagerMock;
@Mock IWifi mWifiMock;
@Mock HalDeviceManager.ManagerStatusListener mManagerStatusListenerMock;
+ @Mock private Clock mClock;
private TestLooper mTestLooper;
+ private Handler mHandler;
private ArgumentCaptor<IHwBinder.DeathRecipient> mDeathRecipientCaptor =
ArgumentCaptor.forClass(IHwBinder.DeathRecipient.class);
private ArgumentCaptor<IServiceNotification.Stub> mServiceNotificationCaptor =
@@ -95,6 +101,10 @@
private WifiStatus mStatusFail;
private class HalDeviceManagerSpy extends HalDeviceManager {
+ HalDeviceManagerSpy() {
+ super(mClock);
+ }
+
@Override
protected IWifi getWifiServiceMockable() {
return mWifiMock;
@@ -111,6 +121,7 @@
MockitoAnnotations.initMocks(this);
mTestLooper = new TestLooper();
+ mHandler = new Handler(mTestLooper.getLooper());
// initialize dummy status objects
mStatusOk = getStatus(WifiStatusCode.SUCCESS);
@@ -141,6 +152,10 @@
dumpDut("after: ");
}
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Chip Independent Tests
+ //////////////////////////////////////////////////////////////////////////////////////
+
/**
* Test basic startup flow:
* - IServiceManager registrations
@@ -196,9 +211,9 @@
HalDeviceManager.ManagerStatusListener.class);
HalDeviceManager.ManagerStatusListener callback2 = mock(
HalDeviceManager.ManagerStatusListener.class);
- mDut.registerStatusListener(callback2, mTestLooper.getLooper());
- mDut.registerStatusListener(callback1, mTestLooper.getLooper());
- mDut.registerStatusListener(callback2, mTestLooper.getLooper());
+ mDut.registerStatusListener(callback2, mHandler);
+ mDut.registerStatusListener(callback1, mHandler);
+ mDut.registerStatusListener(callback2, mHandler);
// startup
executeAndValidateStartupSequence();
@@ -274,555 +289,28 @@
}
/**
- * Validate creation of STA interface from blank start-up. The remove interface.
- */
- @Test
- public void testCreateStaInterfaceNoInitMode() throws Exception {
- final String name = "sta0";
-
- BaselineChip chipMock = new BaselineChip();
- chipMock.initialize();
- mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
- mManagerStatusListenerMock);
- executeAndValidateInitializationSequence();
- executeAndValidateStartupSequence();
-
- HalDeviceManager.InterfaceDestroyedListener idl = mock(
- HalDeviceManager.InterfaceDestroyedListener.class);
- HalDeviceManager.InterfaceAvailableForRequestListener iafrl = mock(
- HalDeviceManager.InterfaceAvailableForRequestListener.class);
-
- IWifiStaIface iface = (IWifiStaIface) validateInterfaceSequence(chipMock,
- false, // chipModeValid
- -1000, // chipModeId (only used if chipModeValid is true)
- IfaceType.STA, // ifaceTypeToCreate
- name, // ifaceName
- BaselineChip.STA_CHIP_MODE_ID, // finalChipMode
- null, // tearDownList
- idl, // destroyedListener
- iafrl // availableListener
- );
- collector.checkThat("allocated interface", iface, IsNull.notNullValue());
-
- // act: remove interface
- mDut.removeIface(iface);
- mTestLooper.dispatchAll();
-
- // verify: callback triggered
- mInOrder.verify(chipMock.chip).removeStaIface(name);
- verify(idl).onDestroyed();
- verify(iafrl).onAvailableForRequest();
-
- verifyNoMoreInteractions(mManagerStatusListenerMock, idl, iafrl);
- }
-
- /**
- * Validate creation of AP interface from blank start-up. The remove interface.
- */
- @Test
- public void testCreateApInterfaceNoInitMode() throws Exception {
- final String name = "ap0";
-
- BaselineChip chipMock = new BaselineChip();
- chipMock.initialize();
- mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
- mManagerStatusListenerMock);
- executeAndValidateInitializationSequence();
- executeAndValidateStartupSequence();
-
- HalDeviceManager.InterfaceDestroyedListener idl = mock(
- HalDeviceManager.InterfaceDestroyedListener.class);
- HalDeviceManager.InterfaceAvailableForRequestListener iafrl = mock(
- HalDeviceManager.InterfaceAvailableForRequestListener.class);
-
- IWifiApIface iface = (IWifiApIface) validateInterfaceSequence(chipMock,
- false, // chipModeValid
- -1000, // chipModeId (only used if chipModeValid is true)
- IfaceType.AP, // ifaceTypeToCreate
- name, // ifaceName
- BaselineChip.AP_CHIP_MODE_ID, // finalChipMode
- null, // tearDownList
- idl, // destroyedListener
- iafrl // availableListener
- );
- collector.checkThat("allocated interface", iface, IsNull.notNullValue());
-
- // act: remove interface
- mDut.removeIface(iface);
- mTestLooper.dispatchAll();
-
- // verify: callback triggered
- mInOrder.verify(chipMock.chip).removeApIface(name);
- verify(idl).onDestroyed();
- verify(iafrl).onAvailableForRequest();
-
- verifyNoMoreInteractions(mManagerStatusListenerMock, idl, iafrl);
- }
-
- /**
- * Validate creation of P2P interface from blank start-up. The remove interface.
- */
- @Test
- public void testCreateP2pInterfaceNoInitMode() throws Exception {
- final String name = "p2p0";
-
- BaselineChip chipMock = new BaselineChip();
- chipMock.initialize();
- mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
- mManagerStatusListenerMock);
- executeAndValidateInitializationSequence();
- executeAndValidateStartupSequence();
-
- HalDeviceManager.InterfaceDestroyedListener idl = mock(
- HalDeviceManager.InterfaceDestroyedListener.class);
- HalDeviceManager.InterfaceAvailableForRequestListener iafrl = mock(
- HalDeviceManager.InterfaceAvailableForRequestListener.class);
-
- IWifiP2pIface iface = (IWifiP2pIface) validateInterfaceSequence(chipMock,
- false, // chipModeValid
- -1000, // chipModeId (only used if chipModeValid is true)
- IfaceType.P2P, // ifaceTypeToCreate
- name, // ifaceName
- BaselineChip.STA_CHIP_MODE_ID, // finalChipMode
- null, // tearDownList
- idl, // destroyedListener
- iafrl // availableListener
- );
- collector.checkThat("allocated interface", iface, IsNull.notNullValue());
-
- // act: remove interface
- mDut.removeIface(iface);
- mTestLooper.dispatchAll();
-
- // verify: callback triggered
- mInOrder.verify(chipMock.chip).removeP2pIface(name);
- verify(idl).onDestroyed();
- verify(iafrl).onAvailableForRequest();
-
- verifyNoMoreInteractions(mManagerStatusListenerMock, idl, iafrl);
- }
-
- /**
- * Validate creation of NAN interface from blank start-up. The remove interface.
- */
- @Test
- public void testCreateNanInterfaceNoInitMode() throws Exception {
- final String name = "nan0";
-
- BaselineChip chipMock = new BaselineChip();
- chipMock.initialize();
- mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
- mManagerStatusListenerMock);
- executeAndValidateInitializationSequence();
- executeAndValidateStartupSequence();
-
- HalDeviceManager.InterfaceDestroyedListener idl = mock(
- HalDeviceManager.InterfaceDestroyedListener.class);
- HalDeviceManager.InterfaceAvailableForRequestListener iafrl = mock(
- HalDeviceManager.InterfaceAvailableForRequestListener.class);
-
- IWifiNanIface iface = (IWifiNanIface) validateInterfaceSequence(chipMock,
- false, // chipModeValid
- -1000, // chipModeId (only used if chipModeValid is true)
- IfaceType.NAN, // ifaceTypeToCreate
- name, // ifaceName
- BaselineChip.STA_CHIP_MODE_ID, // finalChipMode
- null, // tearDownList
- idl, // destroyedListener
- iafrl // availableListener
- );
- collector.checkThat("allocated interface", iface, IsNull.notNullValue());
-
- // act: remove interface
- mDut.removeIface(iface);
- mTestLooper.dispatchAll();
-
- // verify: callback triggered
- mInOrder.verify(chipMock.chip).removeNanIface(name);
- verify(idl).onDestroyed();
- verify(iafrl).onAvailableForRequest();
-
- verifyNoMoreInteractions(mManagerStatusListenerMock, idl, iafrl);
- }
-
- /**
- * Validate creation of AP interface when in STA mode - but with no interface created. Expect
- * a change in chip mode.
- */
- @Test
- public void testCreateApWithStaModeUp() throws Exception {
- final String name = "ap0";
-
- BaselineChip chipMock = new BaselineChip();
- chipMock.initialize();
- mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
- mManagerStatusListenerMock);
- executeAndValidateInitializationSequence();
- executeAndValidateStartupSequence();
-
- HalDeviceManager.InterfaceDestroyedListener idl = mock(
- HalDeviceManager.InterfaceDestroyedListener.class);
- HalDeviceManager.InterfaceAvailableForRequestListener iafrl = mock(
- HalDeviceManager.InterfaceAvailableForRequestListener.class);
-
- IWifiApIface iface = (IWifiApIface) validateInterfaceSequence(chipMock,
- true, // chipModeValid
- BaselineChip.STA_CHIP_MODE_ID, // chipModeId
- IfaceType.AP, // ifaceTypeToCreate
- name, // ifaceName
- BaselineChip.AP_CHIP_MODE_ID, // finalChipMode
- null, // tearDownList
- idl, // destroyedListener
- iafrl // availableListener
- );
- collector.checkThat("allocated interface", iface, IsNull.notNullValue());
-
- // act: stop Wi-Fi
- mDut.stop();
- mTestLooper.dispatchAll();
-
- // verify: callback triggered
- verify(idl).onDestroyed();
- verify(mManagerStatusListenerMock, times(2)).onStatusChanged();
-
- verifyNoMoreInteractions(mManagerStatusListenerMock, idl, iafrl);
- }
-
- /**
- * Validate creation of AP interface when in AP mode - but with no interface created. Expect
- * no change in chip mode.
- */
- @Test
- public void testCreateApWithApModeUp() throws Exception {
- final String name = "ap0";
-
- BaselineChip chipMock = new BaselineChip();
- chipMock.initialize();
- mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
- mManagerStatusListenerMock);
- executeAndValidateInitializationSequence();
- executeAndValidateStartupSequence();
-
- HalDeviceManager.InterfaceDestroyedListener idl = mock(
- HalDeviceManager.InterfaceDestroyedListener.class);
- HalDeviceManager.InterfaceAvailableForRequestListener iafrl = mock(
- HalDeviceManager.InterfaceAvailableForRequestListener.class);
-
- IWifiApIface iface = (IWifiApIface) validateInterfaceSequence(chipMock,
- true, // chipModeValid
- BaselineChip.AP_CHIP_MODE_ID, // chipModeId
- IfaceType.AP, // ifaceTypeToCreate
- name, // ifaceName
- BaselineChip.AP_CHIP_MODE_ID, // finalChipMode
- null, // tearDownList
- idl, // destroyedListener
- iafrl // availableListener
- );
- collector.checkThat("allocated interface", iface, IsNull.notNullValue());
-
- // act: stop Wi-Fi
- mDut.stop();
- mTestLooper.dispatchAll();
-
- // verify: callback triggered
- verify(idl).onDestroyed();
- verify(mManagerStatusListenerMock, times(2)).onStatusChanged();
-
- verifyNoMoreInteractions(mManagerStatusListenerMock, idl, iafrl);
- }
-
- /**
- * Validate AP up/down creation of AP interface when a STA already created. Expect:
- * - STA created
- * - P2P created
- * - When AP requested:
- * - STA & P2P torn down
- * - AP created
- * - P2P creation refused
- * - Request STA: will tear down AP
- * - When AP destroyed:
- * - Get p2p available listener callback
- * - Can create P2P when requested
- * - Create P2P
- * - Request NAN: will get refused
- * - Tear down P2P:
- * - should get nan available listener callback
- * - Can create NAN when requested
- */
- @Test
- public void testCreateSameAndDiffPriorities() throws Exception {
- BaselineChip chipMock = new BaselineChip();
- chipMock.initialize();
- mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
- mManagerStatusListenerMock);
- executeAndValidateInitializationSequence();
- executeAndValidateStartupSequence();
-
- HalDeviceManager.InterfaceDestroyedListener staDestroyedListener = mock(
- HalDeviceManager.InterfaceDestroyedListener.class);
- HalDeviceManager.InterfaceAvailableForRequestListener staAvailListener = mock(
- HalDeviceManager.InterfaceAvailableForRequestListener.class);
-
- HalDeviceManager.InterfaceDestroyedListener staDestroyedListener2 = mock(
- HalDeviceManager.InterfaceDestroyedListener.class);
-
- HalDeviceManager.InterfaceDestroyedListener apDestroyedListener = mock(
- HalDeviceManager.InterfaceDestroyedListener.class);
- HalDeviceManager.InterfaceAvailableForRequestListener apAvailListener = mock(
- HalDeviceManager.InterfaceAvailableForRequestListener.class);
-
- HalDeviceManager.InterfaceDestroyedListener p2pDestroyedListener = mock(
- HalDeviceManager.InterfaceDestroyedListener.class);
- HalDeviceManager.InterfaceAvailableForRequestListener p2pAvailListener = mock(
- HalDeviceManager.InterfaceAvailableForRequestListener.class);
-
- HalDeviceManager.InterfaceDestroyedListener p2pDestroyedListener2 = mock(
- HalDeviceManager.InterfaceDestroyedListener.class);
-
- HalDeviceManager.InterfaceDestroyedListener nanDestroyedListener = mock(
- HalDeviceManager.InterfaceDestroyedListener.class);
- HalDeviceManager.InterfaceAvailableForRequestListener nanAvailListener = mock(
- HalDeviceManager.InterfaceAvailableForRequestListener.class);
-
- // Request STA
- IWifiIface staIface = validateInterfaceSequence(chipMock,
- false, // chipModeValid
- -1000, // chipModeId (only used if chipModeValid is true)
- IfaceType.STA, // ifaceTypeToCreate
- "sta0", // ifaceName
- BaselineChip.STA_CHIP_MODE_ID, // finalChipMode
- null, // tearDownList
- staDestroyedListener, // destroyedListener
- staAvailListener // availableListener
- );
- collector.checkThat("allocated STA interface", staIface, IsNull.notNullValue());
-
- // register additional InterfaceDestroyedListeners - including a duplicate (verify that
- // only called once!)
- mDut.registerDestroyedListener(staIface, staDestroyedListener2, mTestLooper.getLooper());
- mDut.registerDestroyedListener(staIface, staDestroyedListener, mTestLooper.getLooper());
-
- // Request P2P
- IWifiIface p2pIface = validateInterfaceSequence(chipMock,
- true, // chipModeValid
- BaselineChip.STA_CHIP_MODE_ID, // chipModeId
- IfaceType.P2P, // ifaceTypeToCreate
- "p2p0", // ifaceName
- BaselineChip.STA_CHIP_MODE_ID, // finalChipMode
- null, // tearDownList
- p2pDestroyedListener, // destroyedListener
- p2pAvailListener // availableListener
- );
- collector.checkThat("allocated P2P interface", p2pIface, IsNull.notNullValue());
-
- // Request AP
- IWifiIface apIface = validateInterfaceSequence(chipMock,
- true, // chipModeValid
- BaselineChip.STA_CHIP_MODE_ID, // chipModeId
- IfaceType.AP, // ifaceTypeToCreate
- "ap0", // ifaceName
- BaselineChip.AP_CHIP_MODE_ID, // finalChipMode
- new IWifiIface[]{staIface, p2pIface}, // tearDownList
- apDestroyedListener, // destroyedListener
- apAvailListener, // availableListener
- // destroyedInterfacesDestroyedListeners...
- staDestroyedListener, staDestroyedListener2, p2pDestroyedListener
- );
- collector.checkThat("allocated AP interface", apIface, IsNull.notNullValue());
-
- // Request P2P: expect failure
- p2pIface = mDut.createP2pIface(p2pDestroyedListener, mTestLooper.getLooper());
- collector.checkThat("P2P can't be created", p2pIface, IsNull.nullValue());
-
- // Request STA: expect success
- staIface = validateInterfaceSequence(chipMock,
- true, // chipModeValid
- BaselineChip.AP_CHIP_MODE_ID, // chipModeId
- IfaceType.STA, // ifaceTypeToCreate
- "sta0", // ifaceName
- BaselineChip.STA_CHIP_MODE_ID, // finalChipMode
- null, // tearDownList
- staDestroyedListener, // destroyedListener
- staAvailListener, // availableListener
- apDestroyedListener // destroyedInterfacesDestroyedListeners...
- );
- collector.checkThat("allocated STA interface", staIface, IsNull.notNullValue());
-
- mTestLooper.dispatchAll();
- verify(apDestroyedListener).onDestroyed();
-
- // Request P2P: expect success now
- p2pIface = validateInterfaceSequence(chipMock,
- true, // chipModeValid
- BaselineChip.STA_CHIP_MODE_ID, // chipModeId
- IfaceType.P2P, // ifaceTypeToCreate
- "p2p0", // ifaceName
- BaselineChip.STA_CHIP_MODE_ID, // finalChipMode
- null, // tearDownList
- p2pDestroyedListener2, // destroyedListener
- p2pAvailListener // availableListener
- );
-
- // Request NAN: should fail
- IWifiIface nanIface = mDut.createNanIface(nanDestroyedListener, mTestLooper.getLooper());
- mDut.registerInterfaceAvailableForRequestListener(IfaceType.NAN, nanAvailListener,
- mTestLooper.getLooper());
- collector.checkThat("NAN can't be created", nanIface, IsNull.nullValue());
-
- // Tear down P2P
- mDut.removeIface(p2pIface);
- mTestLooper.dispatchAll();
-
- verify(chipMock.chip, times(2)).removeP2pIface("p2p0");
- verify(p2pDestroyedListener2).onDestroyed();
-
- // Should now be able to request and get NAN
- nanIface = validateInterfaceSequence(chipMock,
- true, // chipModeValid
- BaselineChip.STA_CHIP_MODE_ID, // chipModeId
- IfaceType.NAN, // ifaceTypeToCreate
- "nan0", // ifaceName
- BaselineChip.STA_CHIP_MODE_ID, // finalChipMode
- null, // tearDownList
- nanDestroyedListener, // destroyedListener
- nanAvailListener // availableListener
- );
- collector.checkThat("allocated NAN interface", nanIface, IsNull.notNullValue());
-
- // available callback verification
- verify(staAvailListener).onAvailableForRequest();
- verify(apAvailListener, times(4)).onAvailableForRequest();
- verify(p2pAvailListener, times(3)).onAvailableForRequest();
- verify(nanAvailListener).onAvailableForRequest();
-
- verifyNoMoreInteractions(mManagerStatusListenerMock, staDestroyedListener, staAvailListener,
- staDestroyedListener2, apDestroyedListener, apAvailListener, p2pDestroyedListener,
- nanDestroyedListener, nanAvailListener, p2pDestroyedListener2);
- }
-
- /**
- * Validate P2P and NAN interactions. Expect:
- * - STA created
- * - NAN created
- * - When P2P requested:
- * - NAN torn down
- * - P2P created
- * - NAN creation refused
- * - When P2P destroyed:
- * - get nan available listener
- * - Can create NAN when requested
- */
- @Test
- public void testP2pAndNanInteractions() throws Exception {
- BaselineChip chipMock = new BaselineChip();
- chipMock.initialize();
- mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
- mManagerStatusListenerMock);
- executeAndValidateInitializationSequence();
- executeAndValidateStartupSequence();
-
- HalDeviceManager.InterfaceDestroyedListener staDestroyedListener = mock(
- HalDeviceManager.InterfaceDestroyedListener.class);
- HalDeviceManager.InterfaceAvailableForRequestListener staAvailListener = mock(
- HalDeviceManager.InterfaceAvailableForRequestListener.class);
-
- HalDeviceManager.InterfaceDestroyedListener nanDestroyedListener = mock(
- HalDeviceManager.InterfaceDestroyedListener.class);
- HalDeviceManager.InterfaceAvailableForRequestListener nanAvailListener = mock(
- HalDeviceManager.InterfaceAvailableForRequestListener.class);
-
- HalDeviceManager.InterfaceDestroyedListener p2pDestroyedListener = mock(
- HalDeviceManager.InterfaceDestroyedListener.class);
- HalDeviceManager.InterfaceAvailableForRequestListener p2pAvailListener = null;
-
- // Request STA
- IWifiIface staIface = validateInterfaceSequence(chipMock,
- false, // chipModeValid
- -1000, // chipModeId (only used if chipModeValid is true)
- IfaceType.STA, // ifaceTypeToCreate
- "sta0", // ifaceName
- BaselineChip.STA_CHIP_MODE_ID, // finalChipMode
- null, // tearDownList
- staDestroyedListener, // destroyedListener
- staAvailListener // availableListener
- );
-
- // Request NAN
- IWifiIface nanIface = validateInterfaceSequence(chipMock,
- true, // chipModeValid
- BaselineChip.STA_CHIP_MODE_ID, // chipModeId
- IfaceType.NAN, // ifaceTypeToCreate
- "nan0", // ifaceName
- BaselineChip.STA_CHIP_MODE_ID, // finalChipMode
- null, // tearDownList
- nanDestroyedListener, // destroyedListener
- nanAvailListener // availableListener
- );
-
- // Request P2P
- IWifiIface p2pIface = validateInterfaceSequence(chipMock,
- true, // chipModeValid
- BaselineChip.STA_CHIP_MODE_ID, // chipModeId
- IfaceType.P2P, // ifaceTypeToCreate
- "p2p0", // ifaceName
- BaselineChip.STA_CHIP_MODE_ID, // finalChipMode
- new IWifiIface[]{nanIface}, // tearDownList
- p2pDestroyedListener, // destroyedListener
- p2pAvailListener, // availableListener
- nanDestroyedListener // destroyedInterfacesDestroyedListeners...
- );
-
- // Request NAN: expect failure
- nanIface = mDut.createNanIface(nanDestroyedListener, mTestLooper.getLooper());
- mDut.registerInterfaceAvailableForRequestListener(IfaceType.NAN, nanAvailListener,
- mTestLooper.getLooper());
- collector.checkThat("NAN can't be created", nanIface, IsNull.nullValue());
-
- // Destroy P2P interface
- boolean status = mDut.removeIface(p2pIface);
- mInOrder.verify(chipMock.chip).removeP2pIface("p2p0");
- collector.checkThat("P2P removal success", status, equalTo(true));
-
- mTestLooper.dispatchAll();
- verify(p2pDestroyedListener).onDestroyed();
- verify(nanAvailListener).onAvailableForRequest();
-
- // Request NAN: expect success now
- nanIface = validateInterfaceSequence(chipMock,
- true, // chipModeValid
- BaselineChip.STA_CHIP_MODE_ID, // chipModeId
- IfaceType.NAN, // ifaceTypeToCreate
- "nan0", // ifaceName
- BaselineChip.STA_CHIP_MODE_ID, // finalChipMode
- null, // tearDownList
- nanDestroyedListener, // destroyedListener
- nanAvailListener // availableListener
- );
-
- verifyNoMoreInteractions(mManagerStatusListenerMock, staDestroyedListener, staAvailListener,
- nanDestroyedListener, nanAvailListener, p2pDestroyedListener);
- }
-
- /**
* Validates that when (for some reason) the cache is out-of-sync with the actual chip status
* then Wi-Fi is shut-down.
+ *
+ * Uses TestChipV1 - but nothing specific to its configuration. The test validates internal
+ * HDM behavior.
*/
@Test
public void testCacheMismatchError() throws Exception {
- BaselineChip chipMock = new BaselineChip();
+ TestChipV1 chipMock = new TestChipV1();
chipMock.initialize();
mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
mManagerStatusListenerMock);
executeAndValidateInitializationSequence();
executeAndValidateStartupSequence();
- HalDeviceManager.InterfaceDestroyedListener staDestroyedListener = mock(
- HalDeviceManager.InterfaceDestroyedListener.class);
+ InterfaceDestroyedListener staDestroyedListener = mock(
+ InterfaceDestroyedListener.class);
HalDeviceManager.InterfaceAvailableForRequestListener staAvailListener = mock(
HalDeviceManager.InterfaceAvailableForRequestListener.class);
- HalDeviceManager.InterfaceDestroyedListener nanDestroyedListener = mock(
- HalDeviceManager.InterfaceDestroyedListener.class);
+ InterfaceDestroyedListener nanDestroyedListener = mock(
+ InterfaceDestroyedListener.class);
HalDeviceManager.InterfaceAvailableForRequestListener nanAvailListener = mock(
HalDeviceManager.InterfaceAvailableForRequestListener.class);
@@ -832,7 +320,7 @@
-1000, // chipModeId (only used if chipModeValid is true)
IfaceType.STA, // ifaceTypeToCreate
"sta0", // ifaceName
- BaselineChip.STA_CHIP_MODE_ID, // finalChipMode
+ TestChipV1.STA_CHIP_MODE_ID, // finalChipMode
null, // tearDownList
staDestroyedListener, // destroyedListener
staAvailListener // availableListener
@@ -841,10 +329,10 @@
// Request NAN
IWifiIface nanIface = validateInterfaceSequence(chipMock,
true, // chipModeValid
- BaselineChip.STA_CHIP_MODE_ID, // chipModeId
+ TestChipV1.STA_CHIP_MODE_ID, // chipModeId
IfaceType.NAN, // ifaceTypeToCreate
"nan0", // ifaceName
- BaselineChip.STA_CHIP_MODE_ID, // finalChipMode
+ TestChipV1.STA_CHIP_MODE_ID, // finalChipMode
null, // tearDownList
nanDestroyedListener, // destroyedListener
nanAvailListener // availableListener
@@ -854,74 +342,35 @@
chipMock.interfaceNames.get(IfaceType.STA).remove("sta0");
// now try to request another NAN
- nanIface = mDut.createNanIface(nanDestroyedListener, mTestLooper.getLooper());
+ IWifiIface nanIface2 = mDut.createNanIface(nanDestroyedListener, mHandler);
mDut.registerInterfaceAvailableForRequestListener(IfaceType.NAN, nanAvailListener,
- mTestLooper.getLooper());
- collector.checkThat("NAN can't be created", nanIface, IsNull.nullValue());
+ mHandler);
+ collector.checkThat("NAN can't be created", nanIface2, IsNull.nullValue());
// verify that Wi-Fi is shut-down: should also get all onDestroyed messages that are
// registered (even if they seem out-of-sync to chip)
mTestLooper.dispatchAll();
verify(mWifiMock, times(2)).stop();
verify(mManagerStatusListenerMock, times(2)).onStatusChanged();
- verify(staDestroyedListener).onDestroyed();
- verify(nanDestroyedListener).onDestroyed();
+ verify(staDestroyedListener).onDestroyed(getName(staIface));
+ verify(nanDestroyedListener).onDestroyed(getName(nanIface));
verifyNoMoreInteractions(mManagerStatusListenerMock, staDestroyedListener, staAvailListener,
nanDestroyedListener, nanAvailListener);
}
/**
- * Validates that trying to allocate a STA and then another STA fails. Only one STA at a time
- * is permitted (by baseline chip).
- */
- @Test
- public void testDuplicateStaRequests() throws Exception {
- BaselineChip chipMock = new BaselineChip();
- chipMock.initialize();
- mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
- mManagerStatusListenerMock);
- executeAndValidateInitializationSequence();
- executeAndValidateStartupSequence();
-
- HalDeviceManager.InterfaceDestroyedListener staDestroyedListener1 = mock(
- HalDeviceManager.InterfaceDestroyedListener.class);
- HalDeviceManager.InterfaceAvailableForRequestListener staAvailListener1 = mock(
- HalDeviceManager.InterfaceAvailableForRequestListener.class);
-
- HalDeviceManager.InterfaceDestroyedListener staDestroyedListener2 = mock(
- HalDeviceManager.InterfaceDestroyedListener.class);
-
- // get STA interface
- IWifiIface staIface1 = validateInterfaceSequence(chipMock,
- false, // chipModeValid
- -1000, // chipModeId (only used if chipModeValid is true)
- IfaceType.STA, // ifaceTypeToCreate
- "sta0", // ifaceName
- BaselineChip.STA_CHIP_MODE_ID, // finalChipMode
- null, // tearDownList
- staDestroyedListener1, // destroyedListener
- staAvailListener1 // availableListener
- );
- collector.checkThat("STA created", staIface1, IsNull.notNullValue());
-
- // get STA interface again
- IWifiIface staIface2 = mDut.createStaIface(staDestroyedListener2, mTestLooper.getLooper());
- collector.checkThat("STA created", staIface2, IsNull.nullValue());
-
- verifyNoMoreInteractions(mManagerStatusListenerMock, staDestroyedListener1,
- staAvailListener1, staDestroyedListener2);
- }
-
- /**
* Validates that a duplicate registration of the same InterfaceAvailableForRequestListener
* listener will result in a single callback.
*
* Also validates that get an immediate call on registration if available.
+ *
+ * Uses TestChipV1 - but nothing specific to its configuration. The test validates internal
+ * HDM behavior.
*/
@Test
public void testDuplicateAvailableRegistrations() throws Exception {
- BaselineChip chipMock = new BaselineChip();
+ TestChipV1 chipMock = new TestChipV1();
chipMock.initialize();
mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
mManagerStatusListenerMock);
@@ -937,7 +386,7 @@
-1000, // chipModeId (only used if chipModeValid is true)
IfaceType.STA, // ifaceTypeToCreate
"sta0", // ifaceName
- BaselineChip.STA_CHIP_MODE_ID, // finalChipMode
+ TestChipV1.STA_CHIP_MODE_ID, // finalChipMode
null, // tearDownList
null, // destroyedListener
null // availableListener
@@ -946,9 +395,9 @@
// act: register the same listener twice
mDut.registerInterfaceAvailableForRequestListener(IfaceType.STA, staAvailListener,
- mTestLooper.getLooper());
+ mHandler);
mDut.registerInterfaceAvailableForRequestListener(IfaceType.STA, staAvailListener,
- mTestLooper.getLooper());
+ mHandler);
mTestLooper.dispatchAll();
// remove STA interface -> should trigger callbacks
@@ -962,56 +411,6 @@
}
/**
- * Validate that the getSupportedIfaceTypes API works when requesting for all chips.
- */
- @Test
- public void testGetSupportedIfaceTypesAll() throws Exception {
- BaselineChip chipMock = new BaselineChip();
- chipMock.initialize();
- mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
- mManagerStatusListenerMock);
- executeAndValidateInitializationSequence();
- executeAndValidateStartupSequence();
-
- // try API
- Set<Integer> results = mDut.getSupportedIfaceTypes();
-
- // verify results
- Set<Integer> correctResults = new HashSet<>();
- correctResults.add(IfaceType.AP);
- correctResults.add(IfaceType.STA);
- correctResults.add(IfaceType.P2P);
- correctResults.add(IfaceType.NAN);
-
- assertEquals(correctResults, results);
- }
-
- /**
- * Validate that the getSupportedIfaceTypes API works when requesting for a specific chip.
- */
- @Test
- public void testGetSupportedIfaceTypesOneChip() throws Exception {
- BaselineChip chipMock = new BaselineChip();
- chipMock.initialize();
- mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
- mManagerStatusListenerMock);
- executeAndValidateInitializationSequence();
- executeAndValidateStartupSequence();
-
- // try API
- Set<Integer> results = mDut.getSupportedIfaceTypes(chipMock.chip);
-
- // verify results
- Set<Integer> correctResults = new HashSet<>();
- correctResults.add(IfaceType.AP);
- correctResults.add(IfaceType.STA);
- correctResults.add(IfaceType.P2P);
- correctResults.add(IfaceType.NAN);
-
- assertEquals(correctResults, results);
- }
-
- /**
* Validate that when no chip info is found an empty list is returned.
*/
@Test
@@ -1025,15 +424,18 @@
/**
* Test start HAL can retry upon failure.
+ *
+ * Uses TestChipV1 - but nothing specific to its configuration. The test validates internal
+ * HDM behavior.
*/
@Test
public void testStartHalRetryUponNotAvailableFailure() throws Exception {
// Override the stubbing for mWifiMock in before().
when(mWifiMock.start())
- .thenReturn(getStatus(WifiStatusCode.ERROR_NOT_AVAILABLE))
- .thenReturn(mStatusOk);
+ .thenReturn(getStatus(WifiStatusCode.ERROR_NOT_AVAILABLE))
+ .thenReturn(mStatusOk);
- BaselineChip chipMock = new BaselineChip();
+ TestChipV1 chipMock = new TestChipV1();
chipMock.initialize();
mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
mManagerStatusListenerMock);
@@ -1043,13 +445,16 @@
/**
* Test start HAL fails after multiple retry failures.
+ *
+ * Uses TestChipV1 - but nothing specific to its configuration. The test validates internal
+ * HDM behavior.
*/
@Test
public void testStartHalRetryFailUponMultipleNotAvailableFailures() throws Exception {
// Override the stubbing for mWifiMock in before().
when(mWifiMock.start()).thenReturn(getStatus(WifiStatusCode.ERROR_NOT_AVAILABLE));
- BaselineChip chipMock = new BaselineChip();
+ TestChipV1 chipMock = new TestChipV1();
chipMock.initialize();
mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip);
executeAndValidateInitializationSequence();
@@ -1058,13 +463,16 @@
/**
* Test start HAL fails after multiple retry failures.
+ *
+ * Uses TestChipV1 - but nothing specific to its configuration. The test validates internal
+ * HDM behavior.
*/
@Test
public void testStartHalRetryFailUponTrueFailure() throws Exception {
// Override the stubbing for mWifiMock in before().
when(mWifiMock.start()).thenReturn(getStatus(WifiStatusCode.ERROR_UNKNOWN));
- BaselineChip chipMock = new BaselineChip();
+ TestChipV1 chipMock = new TestChipV1();
chipMock.initialize();
mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip);
executeAndValidateInitializationSequence();
@@ -1096,7 +504,856 @@
assertFalse(mDut.isSupported());
}
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Chip Specific Tests - but should work on all chips!
+ // (i.e. add copies for each test chip)
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ // TestChipV1
+
+ /**
+ * Validate creation of STA interface from blank start-up. The remove interface.
+ */
+ @Test
+ public void testCreateStaInterfaceNoInitModeTestChipV1() throws Exception {
+ runCreateSingleXxxInterfaceNoInitMode(new TestChipV1(), IfaceType.STA, "sta0",
+ TestChipV1.STA_CHIP_MODE_ID, 1);
+ }
+
+ /**
+ * Validate creation of AP interface from blank start-up. The remove interface.
+ */
+ @Test
+ public void testCreateApInterfaceNoInitModeTestChipV1() throws Exception {
+ runCreateSingleXxxInterfaceNoInitMode(new TestChipV1(), IfaceType.AP, "ap0",
+ TestChipV1.AP_CHIP_MODE_ID, 1);
+ }
+
+ /**
+ * Validate creation of P2P interface from blank start-up. The remove interface.
+ */
+ @Test
+ public void testCreateP2pInterfaceNoInitModeTestChipV1() throws Exception {
+ runCreateSingleXxxInterfaceNoInitMode(new TestChipV1(), IfaceType.P2P, "p2p0",
+ TestChipV1.STA_CHIP_MODE_ID, 1);
+ }
+
+ /**
+ * Validate creation of NAN interface from blank start-up. The remove interface.
+ */
+ @Test
+ public void testCreateNanInterfaceNoInitModeTestChipV1() throws Exception {
+ runCreateSingleXxxInterfaceNoInitMode(new TestChipV1(), IfaceType.NAN, "nan0",
+ TestChipV1.STA_CHIP_MODE_ID, 1);
+ }
+
+ // TestChipV2
+
+ /**
+ * Validate creation of STA interface from blank start-up. The remove interface.
+ */
+ @Test
+ public void testCreateStaInterfaceNoInitModeTestChipV2() throws Exception {
+ // Note: we expected 2 available callbacks since we now have 2 STAs possible. So
+ // we get callback 1 after creating the first STA (since we can create another STA),
+ // and we get callback 2 after destroying the first STA (since we can create another STA -
+ // as expected).
+ runCreateSingleXxxInterfaceNoInitMode(new TestChipV2(), IfaceType.STA, "sta0",
+ TestChipV2.CHIP_MODE_ID, 2);
+ }
+
+ /**
+ * Validate creation of AP interface from blank start-up. The remove interface.
+ */
+ @Test
+ public void testCreateApInterfaceNoInitModeTestChipV2() throws Exception {
+ runCreateSingleXxxInterfaceNoInitMode(new TestChipV2(), IfaceType.AP, "ap0",
+ TestChipV2.CHIP_MODE_ID, 1);
+ }
+
+ /**
+ * Validate creation of P2P interface from blank start-up. The remove interface.
+ */
+ @Test
+ public void testCreateP2pInterfaceNoInitModeTestChipV2() throws Exception {
+ runCreateSingleXxxInterfaceNoInitMode(new TestChipV2(), IfaceType.P2P, "p2p0",
+ TestChipV2.CHIP_MODE_ID, 1);
+ }
+
+ /**
+ * Validate creation of NAN interface from blank start-up. The remove interface.
+ */
+ @Test
+ public void testCreateNanInterfaceNoInitModeTestChipV2() throws Exception {
+ runCreateSingleXxxInterfaceNoInitMode(new TestChipV2(), IfaceType.NAN, "nan0",
+ TestChipV2.CHIP_MODE_ID, 1);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // TestChipV1 Specific Tests
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Validate creation of AP interface when in STA mode - but with no interface created. Expect
+ * a change in chip mode.
+ */
+ @Test
+ public void testCreateApWithStaModeUpTestChipV1() throws Exception {
+ final String name = "ap0";
+
+ TestChipV1 chipMock = new TestChipV1();
+ chipMock.initialize();
+ mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
+ mManagerStatusListenerMock);
+ executeAndValidateInitializationSequence();
+ executeAndValidateStartupSequence();
+
+ InterfaceDestroyedListener idl = mock(
+ InterfaceDestroyedListener.class);
+ HalDeviceManager.InterfaceAvailableForRequestListener iafrl = mock(
+ HalDeviceManager.InterfaceAvailableForRequestListener.class);
+
+ IWifiApIface iface = (IWifiApIface) validateInterfaceSequence(chipMock,
+ true, // chipModeValid
+ TestChipV1.STA_CHIP_MODE_ID, // chipModeId
+ IfaceType.AP, // ifaceTypeToCreate
+ name, // ifaceName
+ TestChipV1.AP_CHIP_MODE_ID, // finalChipMode
+ null, // tearDownList
+ idl, // destroyedListener
+ iafrl // availableListener
+ );
+ collector.checkThat("allocated interface", iface, IsNull.notNullValue());
+
+ // act: stop Wi-Fi
+ mDut.stop();
+ mTestLooper.dispatchAll();
+
+ // verify: callback triggered
+ verify(idl).onDestroyed(getName(iface));
+ verify(mManagerStatusListenerMock, times(2)).onStatusChanged();
+
+ verifyNoMoreInteractions(mManagerStatusListenerMock, idl, iafrl);
+ }
+
+ /**
+ * Validate creation of AP interface when in STA mode with a single STA iface created.
+ * Expect a change in chip mode.
+ */
+ @Test
+ public void testCreateApWithStIfaceUpTestChipV1UsingNoHandlerListeners() throws Exception {
+ TestChipV1 chipMock = new TestChipV1();
+ chipMock.initialize();
+
+ InterfaceDestroyedListener staIdl = mock(
+ InterfaceDestroyedListener.class);
+ HalDeviceManager.InterfaceAvailableForRequestListener staIafrl = mock(
+ HalDeviceManager.InterfaceAvailableForRequestListener.class);
+ InterfaceDestroyedListener apIdl = mock(
+ InterfaceDestroyedListener.class);
+ HalDeviceManager.InterfaceAvailableForRequestListener apIafrl = mock(
+ HalDeviceManager.InterfaceAvailableForRequestListener.class);
+
+ mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
+ mManagerStatusListenerMock, staIdl, staIafrl, apIdl, apIafrl);
+ executeAndValidateInitializationSequence();
+
+ // Register listener & start Wi-Fi
+ mDut.registerStatusListener(mManagerStatusListenerMock, null);
+ assertTrue(mDut.start());
+ mInOrder.verify(mManagerStatusListenerMock).onStatusChanged();
+
+ mDut.registerInterfaceAvailableForRequestListener(IfaceType.STA, staIafrl, null);
+ mDut.registerInterfaceAvailableForRequestListener(IfaceType.AP, apIafrl, null);
+
+ mInOrder.verify(staIafrl).onAvailableForRequest();
+ mInOrder.verify(apIafrl).onAvailableForRequest();
+
+ // Create STA Iface first.
+ IWifiStaIface staIface = mock(IWifiStaIface.class);
+ doAnswer(new GetNameAnswer("wlan0")).when(staIface).getName(
+ any(IWifiIface.getNameCallback.class));
+ doAnswer(new GetTypeAnswer(IfaceType.STA)).when(staIface).getType(
+ any(IWifiIface.getTypeCallback.class));
+ doAnswer(new CreateXxxIfaceAnswer(chipMock, mStatusOk, staIface)).when(
+ chipMock.chip).createStaIface(any(IWifiChip.createStaIfaceCallback.class));
+ assertEquals(staIface, mDut.createStaIface(staIdl, null));
+
+ mInOrder.verify(chipMock.chip).configureChip(TestChipV1.STA_CHIP_MODE_ID);
+ mInOrder.verify(apIafrl).onAvailableForRequest();
+
+ // Now Create AP Iface.
+ IWifiApIface apIface = mock(IWifiApIface.class);
+ doAnswer(new GetNameAnswer("wlan0")).when(apIface).getName(
+ any(IWifiIface.getNameCallback.class));
+ doAnswer(new GetTypeAnswer(IfaceType.AP)).when(apIface).getType(
+ any(IWifiIface.getTypeCallback.class));
+ doAnswer(new CreateXxxIfaceAnswer(chipMock, mStatusOk, apIface)).when(
+ chipMock.chip).createApIface(any(IWifiChip.createApIfaceCallback.class));
+ assertEquals(apIface, mDut.createApIface(apIdl, null));
+
+ mInOrder.verify(chipMock.chip).removeStaIface(getName(staIface));
+ mInOrder.verify(staIdl).onDestroyed(getName(staIface));
+ mInOrder.verify(chipMock.chip).configureChip(TestChipV1.AP_CHIP_MODE_ID);
+ mInOrder.verify(staIafrl).onAvailableForRequest();
+
+ // Stop Wi-Fi
+ mDut.stop();
+
+ mInOrder.verify(mWifiMock).stop();
+ mInOrder.verify(mManagerStatusListenerMock).onStatusChanged();
+ mInOrder.verify(apIdl).onDestroyed(getName(apIface));
+
+ verifyNoMoreInteractions(mManagerStatusListenerMock, staIdl, staIafrl, apIdl, apIafrl);
+ }
+
+ /**
+ * Validate creation of AP interface when in AP mode - but with no interface created. Expect
+ * no change in chip mode.
+ */
+ @Test
+ public void testCreateApWithApModeUpTestChipV1() throws Exception {
+ final String name = "ap0";
+
+ TestChipV1 chipMock = new TestChipV1();
+ chipMock.initialize();
+ mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
+ mManagerStatusListenerMock);
+ executeAndValidateInitializationSequence();
+ executeAndValidateStartupSequence();
+
+ InterfaceDestroyedListener idl = mock(
+ InterfaceDestroyedListener.class);
+ HalDeviceManager.InterfaceAvailableForRequestListener iafrl = mock(
+ HalDeviceManager.InterfaceAvailableForRequestListener.class);
+
+ IWifiApIface iface = (IWifiApIface) validateInterfaceSequence(chipMock,
+ true, // chipModeValid
+ TestChipV1.AP_CHIP_MODE_ID, // chipModeId
+ IfaceType.AP, // ifaceTypeToCreate
+ name, // ifaceName
+ TestChipV1.AP_CHIP_MODE_ID, // finalChipMode
+ null, // tearDownList
+ idl, // destroyedListener
+ iafrl // availableListener
+ );
+ collector.checkThat("allocated interface", iface, IsNull.notNullValue());
+
+ // act: stop Wi-Fi
+ mDut.stop();
+ mTestLooper.dispatchAll();
+
+ // verify: callback triggered
+ verify(idl).onDestroyed(getName(iface));
+ verify(mManagerStatusListenerMock, times(2)).onStatusChanged();
+
+ verifyNoMoreInteractions(mManagerStatusListenerMock, idl, iafrl);
+ }
+
+ /**
+ * Validate AP up/down creation of AP interface when a STA already created. Expect:
+ * - STA created
+ * - P2P created
+ * - When AP requested:
+ * - STA & P2P torn down
+ * - AP created
+ * - P2P creation refused
+ * - Request STA: will tear down AP
+ * - When AP destroyed:
+ * - Get p2p available listener callback
+ * - Can create P2P when requested
+ * - Create P2P
+ * - Request NAN: will get refused
+ * - Tear down P2P:
+ * - should get nan available listener callback
+ * - Can create NAN when requested
+ */
+ @Test
+ public void testCreateSameAndDiffPrioritiesTestChipV1() throws Exception {
+ TestChipV1 chipMock = new TestChipV1();
+ chipMock.initialize();
+ mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
+ mManagerStatusListenerMock);
+ executeAndValidateInitializationSequence();
+ executeAndValidateStartupSequence();
+
+ InterfaceDestroyedListener staDestroyedListener = mock(
+ InterfaceDestroyedListener.class);
+ HalDeviceManager.InterfaceAvailableForRequestListener staAvailListener = mock(
+ HalDeviceManager.InterfaceAvailableForRequestListener.class);
+
+ InterfaceDestroyedListener staDestroyedListener2 = mock(
+ InterfaceDestroyedListener.class);
+
+ InterfaceDestroyedListener apDestroyedListener = mock(
+ InterfaceDestroyedListener.class);
+ HalDeviceManager.InterfaceAvailableForRequestListener apAvailListener = mock(
+ HalDeviceManager.InterfaceAvailableForRequestListener.class);
+
+ InterfaceDestroyedListener p2pDestroyedListener = mock(
+ InterfaceDestroyedListener.class);
+ HalDeviceManager.InterfaceAvailableForRequestListener p2pAvailListener = mock(
+ HalDeviceManager.InterfaceAvailableForRequestListener.class);
+
+ InterfaceDestroyedListener p2pDestroyedListener2 = mock(
+ InterfaceDestroyedListener.class);
+
+ InterfaceDestroyedListener nanDestroyedListener = mock(
+ InterfaceDestroyedListener.class);
+ HalDeviceManager.InterfaceAvailableForRequestListener nanAvailListener = mock(
+ HalDeviceManager.InterfaceAvailableForRequestListener.class);
+
+ InOrder inOrderStaAvail = inOrder(staAvailListener);
+ InOrder inOrderApAvail = inOrder(apAvailListener);
+ InOrder inOrderP2pAvail = inOrder(p2pAvailListener);
+ InOrder inOrderNanAvail = inOrder(nanAvailListener);
+
+ // register listeners for interface availability
+ mDut.registerInterfaceAvailableForRequestListener(IfaceType.STA, staAvailListener,
+ mHandler);
+ mDut.registerInterfaceAvailableForRequestListener(IfaceType.AP, apAvailListener, mHandler);
+ mDut.registerInterfaceAvailableForRequestListener(IfaceType.P2P, p2pAvailListener,
+ mHandler);
+ mDut.registerInterfaceAvailableForRequestListener(IfaceType.NAN, nanAvailListener,
+ mHandler);
+ mTestLooper.dispatchAll();
+
+ inOrderStaAvail.verify(staAvailListener).onAvailableForRequest();
+ inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
+ inOrderP2pAvail.verify(p2pAvailListener).onAvailableForRequest();
+ inOrderNanAvail.verify(nanAvailListener).onAvailableForRequest();
+
+ // Request STA
+ IWifiIface staIface = validateInterfaceSequence(chipMock,
+ false, // chipModeValid
+ -1000, // chipModeId (only used if chipModeValid is true)
+ IfaceType.STA, // ifaceTypeToCreate
+ "sta0", // ifaceName
+ TestChipV1.STA_CHIP_MODE_ID, // finalChipMode
+ null, // tearDownList
+ staDestroyedListener, // destroyedListener
+ null // availableListener
+ );
+ collector.checkThat("allocated STA interface", staIface, IsNull.notNullValue());
+
+ inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
+ inOrderP2pAvail.verify(p2pAvailListener).onAvailableForRequest();
+ inOrderNanAvail.verify(nanAvailListener).onAvailableForRequest();
+
+ // request STA2: should fail
+ IWifiIface staIface2 = mDut.createStaIface(null, null);
+ collector.checkThat("STA2 should not be created", staIface2, IsNull.nullValue());
+
+ // register additional InterfaceDestroyedListeners - including a duplicate (verify that
+ // only called once!)
+ mDut.registerDestroyedListener(staIface, staDestroyedListener2, mHandler);
+ mDut.registerDestroyedListener(staIface, staDestroyedListener, mHandler);
+
+ // Request P2P
+ IWifiIface p2pIface = validateInterfaceSequence(chipMock,
+ true, // chipModeValid
+ TestChipV1.STA_CHIP_MODE_ID, // chipModeId
+ IfaceType.P2P, // ifaceTypeToCreate
+ "p2p0", // ifaceName
+ TestChipV1.STA_CHIP_MODE_ID, // finalChipMode
+ null, // tearDownList
+ p2pDestroyedListener, // destroyedListener
+ null // availableListener
+ );
+ collector.checkThat("allocated P2P interface", p2pIface, IsNull.notNullValue());
+
+ inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
+
+ // Request AP
+ IWifiIface apIface = validateInterfaceSequence(chipMock,
+ true, // chipModeValid
+ TestChipV1.STA_CHIP_MODE_ID, // chipModeId
+ IfaceType.AP, // ifaceTypeToCreate
+ "ap0", // ifaceName
+ TestChipV1.AP_CHIP_MODE_ID, // finalChipMode
+ new IWifiIface[]{staIface, p2pIface}, // tearDownList
+ apDestroyedListener, // destroyedListener
+ null, // availableListener
+ // destroyedInterfacesDestroyedListeners...
+ new InterfaceDestroyedListenerWithIfaceName(
+ getName(staIface), staDestroyedListener),
+ new InterfaceDestroyedListenerWithIfaceName(
+ getName(staIface), staDestroyedListener2),
+ new InterfaceDestroyedListenerWithIfaceName(
+ getName(p2pIface), p2pDestroyedListener)
+ );
+ collector.checkThat("allocated AP interface", apIface, IsNull.notNullValue());
+
+ inOrderStaAvail.verify(staAvailListener).onAvailableForRequest();
+
+ // request AP2: should fail
+ IWifiIface apIface2 = mDut.createApIface(null, null);
+ collector.checkThat("AP2 should not be created", apIface2, IsNull.nullValue());
+
+ // Request P2P: expect failure
+ p2pIface = mDut.createP2pIface(p2pDestroyedListener, mHandler);
+ collector.checkThat("P2P can't be created", p2pIface, IsNull.nullValue());
+
+ // Request STA: expect success
+ staIface = validateInterfaceSequence(chipMock,
+ true, // chipModeValid
+ TestChipV1.AP_CHIP_MODE_ID, // chipModeId
+ IfaceType.STA, // ifaceTypeToCreate
+ "sta0", // ifaceName
+ TestChipV1.STA_CHIP_MODE_ID, // finalChipMode
+ null, // tearDownList
+ staDestroyedListener, // destroyedListener
+ null, // availableListener
+ // destroyedInterfacesDestroyedListeners...
+ new InterfaceDestroyedListenerWithIfaceName(
+ getName(apIface), apDestroyedListener)
+ );
+ collector.checkThat("allocated STA interface", staIface, IsNull.notNullValue());
+
+ inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
+ inOrderP2pAvail.verify(p2pAvailListener).onAvailableForRequest();
+ inOrderNanAvail.verify(nanAvailListener).onAvailableForRequest();
+
+ mTestLooper.dispatchAll();
+ verify(apDestroyedListener).onDestroyed(getName(apIface));
+
+ // Request P2P: expect success now
+ p2pIface = validateInterfaceSequence(chipMock,
+ true, // chipModeValid
+ TestChipV1.STA_CHIP_MODE_ID, // chipModeId
+ IfaceType.P2P, // ifaceTypeToCreate
+ "p2p0", // ifaceName
+ TestChipV1.STA_CHIP_MODE_ID, // finalChipMode
+ null, // tearDownList
+ p2pDestroyedListener2, // destroyedListener
+ null // availableListener
+ );
+
+ inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
+
+ // Request NAN: should fail
+ IWifiIface nanIface = mDut.createNanIface(nanDestroyedListener, mHandler);
+ mDut.registerInterfaceAvailableForRequestListener(IfaceType.NAN, nanAvailListener,
+ mHandler);
+ collector.checkThat("NAN can't be created", nanIface, IsNull.nullValue());
+
+ // Tear down P2P
+ mDut.removeIface(p2pIface);
+ mTestLooper.dispatchAll();
+
+ inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
+ inOrderP2pAvail.verify(p2pAvailListener).onAvailableForRequest();
+ inOrderNanAvail.verify(nanAvailListener).onAvailableForRequest();
+ verify(chipMock.chip, times(2)).removeP2pIface("p2p0");
+ verify(p2pDestroyedListener2).onDestroyed(getName(p2pIface));
+
+ // Should now be able to request and get NAN
+ nanIface = validateInterfaceSequence(chipMock,
+ true, // chipModeValid
+ TestChipV1.STA_CHIP_MODE_ID, // chipModeId
+ IfaceType.NAN, // ifaceTypeToCreate
+ "nan0", // ifaceName
+ TestChipV1.STA_CHIP_MODE_ID, // finalChipMode
+ null, // tearDownList
+ nanDestroyedListener, // destroyedListener
+ nanAvailListener // availableListener
+ );
+ collector.checkThat("allocated NAN interface", nanIface, IsNull.notNullValue());
+
+ inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
+ inOrderP2pAvail.verify(p2pAvailListener).onAvailableForRequest();
+
+ verifyNoMoreInteractions(mManagerStatusListenerMock, staDestroyedListener, staAvailListener,
+ staDestroyedListener2, apDestroyedListener, apAvailListener, p2pDestroyedListener,
+ nanDestroyedListener, nanAvailListener, p2pDestroyedListener2);
+ }
+
+ /**
+ * Validate P2P and NAN interactions. Expect:
+ * - STA created
+ * - NAN created
+ * - When P2P requested:
+ * - NAN torn down
+ * - P2P created
+ * - NAN creation refused
+ * - When P2P destroyed:
+ * - get nan available listener
+ * - Can create NAN when requested
+ */
+ @Test
+ public void testP2pAndNanInteractionsTestChipV1() throws Exception {
+ runP2pAndNanExclusiveInteractionsTestChip(new TestChipV1(), false,
+ TestChipV1.STA_CHIP_MODE_ID);
+ }
+
+ /**
+ * Validates that trying to allocate a STA and then another STA fails. Only one STA at a time
+ * is permitted (by TestChipV1 chip).
+ */
+ @Test
+ public void testDuplicateStaRequestsTestChipV1() throws Exception {
+ TestChipV1 chipMock = new TestChipV1();
+ chipMock.initialize();
+ mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
+ mManagerStatusListenerMock);
+ executeAndValidateInitializationSequence();
+ executeAndValidateStartupSequence();
+
+ InterfaceDestroyedListener staDestroyedListener1 = mock(
+ InterfaceDestroyedListener.class);
+ HalDeviceManager.InterfaceAvailableForRequestListener staAvailListener1 = mock(
+ HalDeviceManager.InterfaceAvailableForRequestListener.class);
+
+ InterfaceDestroyedListener staDestroyedListener2 = mock(
+ InterfaceDestroyedListener.class);
+
+ // get STA interface
+ IWifiIface staIface1 = validateInterfaceSequence(chipMock,
+ false, // chipModeValid
+ -1000, // chipModeId (only used if chipModeValid is true)
+ IfaceType.STA, // ifaceTypeToCreate
+ "sta0", // ifaceName
+ TestChipV1.STA_CHIP_MODE_ID, // finalChipMode
+ null, // tearDownList
+ staDestroyedListener1, // destroyedListener
+ staAvailListener1 // availableListener
+ );
+ collector.checkThat("STA created", staIface1, IsNull.notNullValue());
+
+ // get STA interface again
+ IWifiIface staIface2 = mDut.createStaIface(staDestroyedListener2, mHandler);
+ collector.checkThat("STA created", staIface2, IsNull.nullValue());
+
+ verifyNoMoreInteractions(mManagerStatusListenerMock, staDestroyedListener1,
+ staAvailListener1, staDestroyedListener2);
+ }
+
+ /**
+ * Validate that the getSupportedIfaceTypes API works when requesting for all chips.
+ */
+ @Test
+ public void testGetSupportedIfaceTypesAllTestChipV1() throws Exception {
+ TestChipV1 chipMock = new TestChipV1();
+ chipMock.initialize();
+ mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
+ mManagerStatusListenerMock);
+ executeAndValidateInitializationSequence();
+ executeAndValidateStartupSequence();
+
+ // try API
+ Set<Integer> results = mDut.getSupportedIfaceTypes();
+
+ // verify results
+ Set<Integer> correctResults = new HashSet<>();
+ correctResults.add(IfaceType.AP);
+ correctResults.add(IfaceType.STA);
+ correctResults.add(IfaceType.P2P);
+ correctResults.add(IfaceType.NAN);
+
+ assertEquals(correctResults, results);
+ }
+
+ /**
+ * Validate that the getSupportedIfaceTypes API works when requesting for a specific chip.
+ */
+ @Test
+ public void testGetSupportedIfaceTypesOneChipTestChipV1() throws Exception {
+ TestChipV1 chipMock = new TestChipV1();
+ chipMock.initialize();
+ mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
+ mManagerStatusListenerMock);
+ executeAndValidateInitializationSequence();
+ executeAndValidateStartupSequence();
+
+ // try API
+ Set<Integer> results = mDut.getSupportedIfaceTypes(chipMock.chip);
+
+ // verify results
+ Set<Integer> correctResults = new HashSet<>();
+ correctResults.add(IfaceType.AP);
+ correctResults.add(IfaceType.STA);
+ correctResults.add(IfaceType.P2P);
+ correctResults.add(IfaceType.NAN);
+
+ assertEquals(correctResults, results);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // TestChipV2 Specific Tests
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Validate a flow sequence for test chip 2:
+ * - create STA
+ * - create P2P
+ * - request NAN: failure
+ * - create AP
+ * - create STA: will get refused
+ * - create AP: will get refused
+ * - tear down AP
+ * - create STA
+ * - create STA: will get refused
+ * - create AP: should get created and the last created STA should get destroyed
+ * - tear down P2P
+ * - create NAN
+ */
+ @Test
+ public void testInterfaceCreationFlowTestChipV2() throws Exception {
+ TestChipV2 chipMock = new TestChipV2();
+ chipMock.initialize();
+ mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
+ mManagerStatusListenerMock);
+ executeAndValidateInitializationSequence();
+ executeAndValidateStartupSequence();
+
+ InterfaceDestroyedListener staDestroyedListener = mock(
+ InterfaceDestroyedListener.class);
+ InterfaceDestroyedListener staDestroyedListener2 = mock(
+ InterfaceDestroyedListener.class);
+ HalDeviceManager.InterfaceAvailableForRequestListener staAvailListener = mock(
+ HalDeviceManager.InterfaceAvailableForRequestListener.class);
+
+ InterfaceDestroyedListener apDestroyedListener = mock(
+ InterfaceDestroyedListener.class);
+ HalDeviceManager.InterfaceAvailableForRequestListener apAvailListener = mock(
+ HalDeviceManager.InterfaceAvailableForRequestListener.class);
+
+ InterfaceDestroyedListener p2pDestroyedListener = mock(
+ InterfaceDestroyedListener.class);
+ HalDeviceManager.InterfaceAvailableForRequestListener p2pAvailListener = mock(
+ HalDeviceManager.InterfaceAvailableForRequestListener.class);
+
+ InterfaceDestroyedListener nanDestroyedListener = mock(
+ InterfaceDestroyedListener.class);
+ HalDeviceManager.InterfaceAvailableForRequestListener nanAvailListener = mock(
+ HalDeviceManager.InterfaceAvailableForRequestListener.class);
+
+ InOrder inOrderStaAvail = inOrder(staAvailListener);
+ InOrder inOrderApAvail = inOrder(apAvailListener);
+ InOrder inOrderP2pAvail = inOrder(p2pAvailListener);
+ InOrder inOrderNanAvail = inOrder(nanAvailListener);
+
+ // register listeners for interface availability
+ mDut.registerInterfaceAvailableForRequestListener(IfaceType.STA, staAvailListener,
+ mHandler);
+ mDut.registerInterfaceAvailableForRequestListener(IfaceType.AP, apAvailListener, mHandler);
+ mDut.registerInterfaceAvailableForRequestListener(IfaceType.P2P, p2pAvailListener,
+ mHandler);
+ mDut.registerInterfaceAvailableForRequestListener(IfaceType.NAN, nanAvailListener,
+ mHandler);
+ mTestLooper.dispatchAll();
+
+ inOrderStaAvail.verify(staAvailListener).onAvailableForRequest();
+ inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
+ inOrderP2pAvail.verify(p2pAvailListener).onAvailableForRequest();
+ inOrderNanAvail.verify(nanAvailListener).onAvailableForRequest();
+
+ // create STA
+ when(mClock.getUptimeSinceBootMillis()).thenReturn(15L);
+ IWifiIface staIface = validateInterfaceSequence(chipMock,
+ false, // chipModeValid
+ -1000, // chipModeId (only used if chipModeValid is true)
+ IfaceType.STA, // ifaceTypeToCreate
+ "sta0", // ifaceName
+ TestChipV2.CHIP_MODE_ID, // finalChipMode
+ null, // tearDownList
+ staDestroyedListener, // destroyedListener
+ null // availableListener (already registered)
+ );
+ collector.checkThat("STA interface wasn't created", staIface, IsNull.notNullValue());
+
+ inOrderStaAvail.verify(staAvailListener).onAvailableForRequest();
+ inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
+ inOrderP2pAvail.verify(p2pAvailListener).onAvailableForRequest();
+ inOrderNanAvail.verify(nanAvailListener).onAvailableForRequest();
+
+ // create P2P
+ IWifiIface p2pIface = validateInterfaceSequence(chipMock,
+ true, // chipModeValid
+ TestChipV2.CHIP_MODE_ID, // chipModeId
+ IfaceType.P2P, // ifaceTypeToCreate
+ "p2p0", // ifaceName
+ TestChipV2.CHIP_MODE_ID, // finalChipMode
+ null, // tearDownList
+ p2pDestroyedListener, // destroyedListener
+ null // availableListener (already registered)
+ );
+ collector.checkThat("P2P interface wasn't created", p2pIface, IsNull.notNullValue());
+
+ inOrderStaAvail.verify(staAvailListener).onAvailableForRequest();
+ inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
+
+ // request NAN: should fail
+ IWifiIface nanIface = mDut.createNanIface(null, null);
+ collector.checkThat("NAN should not be created", nanIface, IsNull.nullValue());
+
+ // create AP
+ IWifiIface apIface = validateInterfaceSequence(chipMock,
+ true, // chipModeValid
+ TestChipV2.CHIP_MODE_ID, // chipModeId
+ IfaceType.AP, // ifaceTypeToCreate
+ "ap0", // ifaceName
+ TestChipV2.CHIP_MODE_ID, // finalChipMode
+ null, // tearDownList
+ apDestroyedListener, // destroyedListener
+ null // availableListener (already registered)
+ );
+ collector.checkThat("AP interface wasn't created", apIface, IsNull.notNullValue());
+
+ // request STA2: should fail
+ IWifiIface staIface2 = mDut.createStaIface(null, null);
+ collector.checkThat("STA2 should not be created", staIface2, IsNull.nullValue());
+
+ // request AP2: should fail
+ IWifiIface apIface2 = mDut.createApIface(null, null);
+ collector.checkThat("AP2 should not be created", apIface2, IsNull.nullValue());
+
+ // tear down AP
+ mDut.removeIface(apIface);
+ mTestLooper.dispatchAll();
+
+ inOrderStaAvail.verify(staAvailListener).onAvailableForRequest();
+ inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
+ verify(chipMock.chip).removeApIface("ap0");
+ verify(apDestroyedListener).onDestroyed(getName(apIface));
+
+ // create STA2: using a later clock
+ when(mClock.getUptimeSinceBootMillis()).thenReturn(20L);
+ staIface2 = validateInterfaceSequence(chipMock,
+ true, // chipModeValid
+ TestChipV2.CHIP_MODE_ID, // chipModeId
+ IfaceType.STA, // ifaceTypeToCreate
+ "sta1", // ifaceName
+ TestChipV2.CHIP_MODE_ID, // finalChipMode
+ null, // tearDownList
+ staDestroyedListener2, // destroyedListener
+ null // availableListener (already registered)
+ );
+ collector.checkThat("STA 2 interface wasn't created", staIface2, IsNull.notNullValue());
+
+ inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
+
+ // request STA3: should fail
+ IWifiIface staIface3 = mDut.createStaIface(null, null);
+ collector.checkThat("STA3 should not be created", staIface3, IsNull.nullValue());
+
+ // create AP - this will destroy the last STA created, i.e. STA2
+ apIface = validateInterfaceSequence(chipMock,
+ true, // chipModeValid
+ TestChipV2.CHIP_MODE_ID, // chipModeId
+ IfaceType.AP, // ifaceTypeToCreate
+ "ap0", // ifaceName
+ TestChipV2.CHIP_MODE_ID, // finalChipMode
+ null, // tearDownList
+ apDestroyedListener, // destroyedListener
+ null, // availableListener (already registered),
+ // destroyedInterfacesDestroyedListeners...
+ new InterfaceDestroyedListenerWithIfaceName(
+ getName(staIface2), staDestroyedListener2)
+ );
+ collector.checkThat("AP interface wasn't created", apIface, IsNull.notNullValue());
+
+ // tear down P2P
+ mDut.removeIface(p2pIface);
+ mTestLooper.dispatchAll();
+
+ inOrderP2pAvail.verify(p2pAvailListener).onAvailableForRequest();
+ inOrderNanAvail.verify(nanAvailListener).onAvailableForRequest();
+ verify(chipMock.chip).removeP2pIface("p2p0");
+ verify(p2pDestroyedListener).onDestroyed(getName(p2pIface));
+
+ // create NAN
+ nanIface = validateInterfaceSequence(chipMock,
+ true, // chipModeValid
+ TestChipV2.CHIP_MODE_ID, // chipModeId
+ IfaceType.NAN, // ifaceTypeToCreate
+ "nan0", // ifaceName
+ TestChipV2.CHIP_MODE_ID, // finalChipMode
+ null, // tearDownList
+ nanDestroyedListener, // destroyedListener
+ null // availableListener (already registered)
+ );
+ collector.checkThat("NAN interface wasn't created", nanIface, IsNull.notNullValue());
+
+ inOrderP2pAvail.verify(p2pAvailListener).onAvailableForRequest();
+
+ verifyNoMoreInteractions(mManagerStatusListenerMock, staDestroyedListener,
+ staDestroyedListener2, apDestroyedListener, p2pDestroyedListener,
+ nanDestroyedListener, staAvailListener, apAvailListener, p2pAvailListener,
+ nanAvailListener, staAvailListener, apAvailListener, p2pAvailListener,
+ nanAvailListener);
+ }
+
+ /**
+ * Validate P2P and NAN interactions. Expect:
+ * - STA created
+ * - NAN created
+ * - When P2P requested:
+ * - NAN torn down
+ * - P2P created
+ * - NAN creation refused
+ * - When P2P destroyed:
+ * - get nan available listener
+ * - Can create NAN when requested
+ */
+ @Test
+ public void testP2pAndNanInteractionsTestChipV2() throws Exception {
+ runP2pAndNanExclusiveInteractionsTestChip(new TestChipV2(), true, TestChipV2.CHIP_MODE_ID);
+ }
+
+ /**
+ * Validate that the getSupportedIfaceTypes API works when requesting for all chips.
+ */
+ @Test
+ public void testGetSupportedIfaceTypesAllTestChipV2() throws Exception {
+ TestChipV2 chipMock = new TestChipV2();
+ chipMock.initialize();
+ mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
+ mManagerStatusListenerMock);
+ executeAndValidateInitializationSequence();
+ executeAndValidateStartupSequence();
+
+ // try API
+ Set<Integer> results = mDut.getSupportedIfaceTypes();
+
+ // verify results
+ Set<Integer> correctResults = new HashSet<>();
+ correctResults.add(IfaceType.AP);
+ correctResults.add(IfaceType.STA);
+ correctResults.add(IfaceType.P2P);
+ correctResults.add(IfaceType.NAN);
+
+ assertEquals(correctResults, results);
+ }
+
+ /**
+ * Validate that the getSupportedIfaceTypes API works when requesting for a specific chip.
+ */
+ @Test
+ public void testGetSupportedIfaceTypesOneChipTestChipV2() throws Exception {
+ TestChipV2 chipMock = new TestChipV2();
+ chipMock.initialize();
+ mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
+ mManagerStatusListenerMock);
+ executeAndValidateInitializationSequence();
+ executeAndValidateStartupSequence();
+
+ // try API
+ Set<Integer> results = mDut.getSupportedIfaceTypes(chipMock.chip);
+
+ // verify results
+ Set<Integer> correctResults = new HashSet<>();
+ correctResults.add(IfaceType.AP);
+ correctResults.add(IfaceType.STA);
+ correctResults.add(IfaceType.P2P);
+ correctResults.add(IfaceType.NAN);
+
+ assertEquals(correctResults, results);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////
// utilities
+ ///////////////////////////////////////////////////////////////////////////////////////
private void dumpDut(String prefix) {
StringWriter sw = new StringWriter();
mDut.dump(null, new PrintWriter(sw), null);
@@ -1140,7 +1397,7 @@
private void executeAndValidateStartupSequence(int numAttempts, boolean success)
throws Exception {
// act: register listener & start Wi-Fi
- mDut.registerStatusListener(mManagerStatusListenerMock, mTestLooper.getLooper());
+ mDut.registerStatusListener(mManagerStatusListenerMock, mHandler);
collector.checkThat(mDut.start(), equalTo(success));
// verify
@@ -1156,12 +1413,175 @@
}
}
+ private void runCreateSingleXxxInterfaceNoInitMode(ChipMockBase chipMock, int ifaceTypeToCreate,
+ String ifaceName, int finalChipMode, int expectedAvailableCalls) throws Exception {
+ chipMock.initialize();
+ mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
+ mManagerStatusListenerMock);
+ executeAndValidateInitializationSequence();
+ executeAndValidateStartupSequence();
+
+ InterfaceDestroyedListener idl = mock(
+ InterfaceDestroyedListener.class);
+ HalDeviceManager.InterfaceAvailableForRequestListener iafrl = mock(
+ HalDeviceManager.InterfaceAvailableForRequestListener.class);
+
+ IWifiIface iface = validateInterfaceSequence(chipMock,
+ false, // chipModeValid
+ -1000, // chipModeId (only used if chipModeValid is true)
+ ifaceTypeToCreate,
+ ifaceName,
+ finalChipMode,
+ null, // tearDownList
+ idl, // destroyedListener
+ iafrl // availableListener
+ );
+ collector.checkThat("allocated interface", iface, IsNull.notNullValue());
+
+ // act: remove interface
+ mDut.removeIface(iface);
+ mTestLooper.dispatchAll();
+
+ // verify: callback triggered
+ switch (ifaceTypeToCreate) {
+ case IfaceType.STA:
+ mInOrder.verify(chipMock.chip).removeStaIface(ifaceName);
+ break;
+ case IfaceType.AP:
+ mInOrder.verify(chipMock.chip).removeApIface(ifaceName);
+ break;
+ case IfaceType.P2P:
+ mInOrder.verify(chipMock.chip).removeP2pIface(ifaceName);
+ break;
+ case IfaceType.NAN:
+ mInOrder.verify(chipMock.chip).removeNanIface(ifaceName);
+ break;
+ }
+
+ verify(idl).onDestroyed(ifaceName);
+ verify(iafrl, times(expectedAvailableCalls)).onAvailableForRequest();
+
+ verifyNoMoreInteractions(mManagerStatusListenerMock, idl, iafrl);
+ }
+
+ /**
+ * Validate P2P and NAN interactions. Expect:
+ * - STA created
+ * - NAN created
+ * - When P2P requested:
+ * - NAN torn down
+ * - P2P created
+ * - NAN creation refused
+ * - When P2P destroyed:
+ * - get nan available listener
+ * - Can create NAN when requested
+ *
+ * Relevant for any chip which supports STA + NAN || P2P (or a richer combination - but bottom
+ * line of NAN and P2P being exclusive).
+ */
+ public void runP2pAndNanExclusiveInteractionsTestChip(ChipMockBase chipMock,
+ boolean duplicateStas, int onlyChipMode) throws Exception {
+ chipMock.initialize();
+ mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
+ mManagerStatusListenerMock);
+ executeAndValidateInitializationSequence();
+ executeAndValidateStartupSequence();
+
+ InterfaceDestroyedListener staDestroyedListener = mock(
+ InterfaceDestroyedListener.class);
+ HalDeviceManager.InterfaceAvailableForRequestListener staAvailListener = mock(
+ HalDeviceManager.InterfaceAvailableForRequestListener.class);
+
+ InterfaceDestroyedListener nanDestroyedListener = mock(
+ InterfaceDestroyedListener.class);
+ HalDeviceManager.InterfaceAvailableForRequestListener nanAvailListener = mock(
+ HalDeviceManager.InterfaceAvailableForRequestListener.class);
+
+ InterfaceDestroyedListener p2pDestroyedListener = mock(
+ InterfaceDestroyedListener.class);
+ HalDeviceManager.InterfaceAvailableForRequestListener p2pAvailListener = null;
+
+ // Request STA
+ IWifiIface staIface = validateInterfaceSequence(chipMock,
+ false, // chipModeValid
+ -1000, // chipModeId (only used if chipModeValid is true)
+ IfaceType.STA, // ifaceTypeToCreate
+ "sta0", // ifaceName
+ onlyChipMode, // finalChipMode
+ null, // tearDownList
+ staDestroyedListener, // destroyedListener
+ staAvailListener // availableListener
+ );
+
+ // Request NAN
+ IWifiIface nanIface = validateInterfaceSequence(chipMock,
+ true, // chipModeValid
+ onlyChipMode, // chipModeId
+ IfaceType.NAN, // ifaceTypeToCreate
+ "nan0", // ifaceName
+ onlyChipMode, // finalChipMode
+ null, // tearDownList
+ nanDestroyedListener, // destroyedListener
+ nanAvailListener // availableListener
+ );
+
+ // Request P2P
+ IWifiIface p2pIface = validateInterfaceSequence(chipMock,
+ true, // chipModeValid
+ onlyChipMode, // chipModeId
+ IfaceType.P2P, // ifaceTypeToCreate
+ "p2p0", // ifaceName
+ onlyChipMode, // finalChipMode
+ new IWifiIface[]{nanIface}, // tearDownList
+ p2pDestroyedListener, // destroyedListener
+ p2pAvailListener, // availableListener
+ // destroyedInterfacesDestroyedListeners...
+ new InterfaceDestroyedListenerWithIfaceName(
+ getName(nanIface), nanDestroyedListener)
+ );
+
+ // Request NAN: expect failure
+ nanIface = mDut.createNanIface(nanDestroyedListener, mHandler);
+ mDut.registerInterfaceAvailableForRequestListener(IfaceType.NAN, nanAvailListener,
+ mHandler);
+ collector.checkThat("NAN can't be created", nanIface, IsNull.nullValue());
+
+ // Destroy P2P interface
+ boolean status = mDut.removeIface(p2pIface);
+ mInOrder.verify(chipMock.chip).removeP2pIface("p2p0");
+ collector.checkThat("P2P removal success", status, equalTo(true));
+
+ mTestLooper.dispatchAll();
+ verify(p2pDestroyedListener).onDestroyed(getName(p2pIface));
+ verify(nanAvailListener).onAvailableForRequest();
+
+ // Request NAN: expect success now
+ nanIface = validateInterfaceSequence(chipMock,
+ true, // chipModeValid
+ onlyChipMode, // chipModeId
+ IfaceType.NAN, // ifaceTypeToCreate
+ "nan0", // ifaceName
+ onlyChipMode, // finalChipMode
+ null, // tearDownList
+ nanDestroyedListener, // destroyedListener
+ nanAvailListener // availableListener
+ );
+
+ if (duplicateStas) {
+ // if there are duplicate STAs then expect an available callback for each step above
+ verify(staAvailListener, times(5)).onAvailableForRequest();
+ }
+
+ verifyNoMoreInteractions(mManagerStatusListenerMock, staDestroyedListener, staAvailListener,
+ nanDestroyedListener, nanAvailListener, p2pDestroyedListener);
+ }
+
private IWifiIface validateInterfaceSequence(ChipMockBase chipMock,
boolean chipModeValid, int chipModeId,
int ifaceTypeToCreate, String ifaceName, int finalChipMode, IWifiIface[] tearDownList,
- HalDeviceManager.InterfaceDestroyedListener destroyedListener,
+ InterfaceDestroyedListener destroyedListener,
HalDeviceManager.InterfaceAvailableForRequestListener availableListener,
- HalDeviceManager.InterfaceDestroyedListener... destroyedInterfacesDestroyedListeners)
+ InterfaceDestroyedListenerWithIfaceName...destroyedInterfacesDestroyedListeners)
throws Exception {
// configure chip mode response
chipMock.chipModeValid = chipModeValid;
@@ -1181,7 +1601,7 @@
doAnswer(new CreateXxxIfaceAnswer(chipMock, mStatusOk, iface)).when(
chipMock.chip).createStaIface(any(IWifiChip.createStaIfaceCallback.class));
- mDut.createStaIface(destroyedListener, mTestLooper.getLooper());
+ mDut.createStaIface(destroyedListener, mHandler);
break;
case IfaceType.AP:
iface = mock(IWifiApIface.class);
@@ -1192,7 +1612,7 @@
doAnswer(new CreateXxxIfaceAnswer(chipMock, mStatusOk, iface)).when(
chipMock.chip).createApIface(any(IWifiChip.createApIfaceCallback.class));
- mDut.createApIface(destroyedListener, mTestLooper.getLooper());
+ mDut.createApIface(destroyedListener, mHandler);
break;
case IfaceType.P2P:
iface = mock(IWifiP2pIface.class);
@@ -1203,7 +1623,7 @@
doAnswer(new CreateXxxIfaceAnswer(chipMock, mStatusOk, iface)).when(
chipMock.chip).createP2pIface(any(IWifiChip.createP2pIfaceCallback.class));
- mDut.createP2pIface(destroyedListener, mTestLooper.getLooper());
+ mDut.createP2pIface(destroyedListener, mHandler);
break;
case IfaceType.NAN:
iface = mock(IWifiNanIface.class);
@@ -1214,12 +1634,12 @@
doAnswer(new CreateXxxIfaceAnswer(chipMock, mStatusOk, iface)).when(
chipMock.chip).createNanIface(any(IWifiChip.createNanIfaceCallback.class));
- mDut.createNanIface(destroyedListener, mTestLooper.getLooper());
+ mDut.createNanIface(destroyedListener, mHandler);
break;
}
if (availableListener != null) {
mDut.registerInterfaceAvailableForRequestListener(ifaceTypeToCreate, availableListener,
- mTestLooper.getLooper());
+ mHandler);
}
// validate: optional tear down of interfaces
@@ -1272,9 +1692,8 @@
// verify: callbacks on deleted interfaces
mTestLooper.dispatchAll();
for (int i = 0; i < destroyedInterfacesDestroyedListeners.length; ++i) {
- verify(destroyedInterfacesDestroyedListeners[i]).onDestroyed();
+ destroyedInterfacesDestroyedListeners[i].validate();
}
-
return iface;
}
@@ -1300,6 +1719,21 @@
return status;
}
+ private static class InterfaceDestroyedListenerWithIfaceName {
+ private final String mIfaceName;
+ @Mock private final InterfaceDestroyedListener mListener;
+
+ InterfaceDestroyedListenerWithIfaceName(
+ String ifaceName, InterfaceDestroyedListener listener) {
+ mIfaceName = ifaceName;
+ mListener = listener;
+ }
+
+ public void validate() {
+ verify(mListener).onDestroyed(mIfaceName);
+ }
+ }
+
private static class Mutable<E> {
public E value;
@@ -1598,10 +2032,10 @@
}
}
- // emulate baseline/legacy config:
- // mode: STA + NAN || P2P
- // mode: NAN
- private class BaselineChip extends ChipMockBase {
+ // test chip configuration V1:
+ // mode: STA + (NAN || P2P)
+ // mode: AP
+ private class TestChipV1 extends ChipMockBase {
static final int STA_CHIP_MODE_ID = 0;
static final int AP_CHIP_MODE_ID = 1;
@@ -1659,4 +2093,60 @@
.getAvailableModes(any(IWifiChip.getAvailableModesCallback.class));
}
}
+
+ // test chip configuration V2:
+ // mode: STA + (STA || AP) + (NAN || P2P)
+ private class TestChipV2 extends ChipMockBase {
+ // only mode (different number from any in TestChipV1 so can catch test errors)
+ static final int CHIP_MODE_ID = 5;
+
+ void initialize() throws Exception {
+ super.initialize();
+
+ // chip Id configuration
+ ArrayList<Integer> chipIds;
+ chipId = 12;
+ chipIds = new ArrayList<>();
+ chipIds.add(chipId);
+ doAnswer(new GetChipIdsAnswer(mStatusOk, chipIds)).when(mWifiMock).getChipIds(
+ any(IWifi.getChipIdsCallback.class));
+
+ doAnswer(new GetChipAnswer(mStatusOk, chip)).when(mWifiMock).getChip(eq(12),
+ any(IWifi.getChipCallback.class));
+
+ // initialize dummy chip modes
+ IWifiChip.ChipMode cm;
+ IWifiChip.ChipIfaceCombination cic;
+ IWifiChip.ChipIfaceCombinationLimit cicl;
+
+ // Mode 0 (only one): 1xSTA + 1x{STA,AP} + 1x{P2P,NAN}
+ availableModes = new ArrayList<>();
+ cm = new IWifiChip.ChipMode();
+ cm.id = CHIP_MODE_ID;
+
+ cic = new IWifiChip.ChipIfaceCombination();
+
+ cicl = new IWifiChip.ChipIfaceCombinationLimit();
+ cicl.maxIfaces = 1;
+ cicl.types.add(IfaceType.STA);
+ cic.limits.add(cicl);
+
+ cicl = new IWifiChip.ChipIfaceCombinationLimit();
+ cicl.maxIfaces = 1;
+ cicl.types.add(IfaceType.STA);
+ cicl.types.add(IfaceType.AP);
+ cic.limits.add(cicl);
+
+ cicl = new IWifiChip.ChipIfaceCombinationLimit();
+ cicl.maxIfaces = 1;
+ cicl.types.add(IfaceType.P2P);
+ cicl.types.add(IfaceType.NAN);
+ cic.limits.add(cicl);
+ cm.availableCombinations.add(cic);
+ availableModes.add(cm);
+
+ doAnswer(new GetAvailableModesAnswer(this)).when(chip)
+ .getAvailableModes(any(IWifiChip.getAvailableModesCallback.class));
+ }
+ }
}
diff --git a/tests/wifitests/src/com/android/server/wifi/PasspointProvisioningTestUtil.java b/tests/wifitests/src/com/android/server/wifi/PasspointProvisioningTestUtil.java
new file mode 100644
index 0000000..c78135d
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/PasspointProvisioningTestUtil.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wifi.hotspot2;
+
+import android.graphics.drawable.Icon;
+import android.net.Uri;
+import android.net.wifi.WifiSsid;
+import android.net.wifi.hotspot2.OsuProvider;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Helper for creating and populating WifiConfigurations in unit tests.
+ */
+public class PasspointProvisioningTestUtil {
+ /**
+ * These are constants used to generate predefined OsuProvider.
+ */
+ public static final WifiSsid TEST_SSID =
+ WifiSsid.createFromByteArray("TEST SSID".getBytes(StandardCharsets.UTF_8));
+ public static final String TEST_FRIENDLY_NAME = "Friendly Name";
+ public static final String TEST_SERVICE_DESCRIPTION = "Dummy Service";
+ public static final Uri TEST_SERVER_URI = Uri.parse("https://test.com");
+ public static final String TEST_NAI = "test.access.com";
+ public static final List<Integer> TEST_METHOD_LIST =
+ Arrays.asList(OsuProvider.METHOD_SOAP_XML_SPP);
+ public static final Icon TEST_ICON = Icon.createWithData(new byte[10], 0, 10);
+
+ /**
+ * Construct a {@link android.net.wifi.hotspot2.OsuProvider}.
+ * @param openOsuAP indicates if the OSU AP belongs to an open or OSEN network
+ * @return the constructed {@link android.net.wifi.hotspot2.OsuProvider}
+ */
+ public static OsuProvider generateOsuProvider(boolean openOsuAP) {
+ if (openOsuAP) {
+ return new OsuProvider(TEST_SSID, TEST_FRIENDLY_NAME, TEST_SERVICE_DESCRIPTION,
+ TEST_SERVER_URI, null, TEST_METHOD_LIST, TEST_ICON);
+ } else {
+ return new OsuProvider(TEST_SSID, TEST_FRIENDLY_NAME, TEST_SERVICE_DESCRIPTION,
+ TEST_SERVER_URI, TEST_NAI, TEST_METHOD_LIST, TEST_ICON);
+ }
+ }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java b/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java
index 892b597..cda9cf5 100644
--- a/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java
@@ -16,22 +16,31 @@
package com.android.server.wifi;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyBoolean;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
+import static android.net.wifi.WifiConfiguration.KeyMgmt.WPA_PSK;
+import static android.net.wifi.WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE;
+import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_FAILURE_REASON;
+import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
+import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
+import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE;
+import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
+import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING;
+import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
+import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING;
+import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED;
+import static com.android.server.wifi.LocalOnlyHotspotRequestInfo.HOTSPOT_NO_ERROR;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.*;
+
+import android.content.Context;
+import android.content.Intent;
import android.net.InterfaceConfiguration;
import android.net.wifi.IApInterface;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
-import android.os.IBinder;
-import android.os.IBinder.DeathRecipient;
import android.os.INetworkManagementService;
+import android.os.UserHandle;
import android.os.test.TestLooper;
import android.test.suitebuilder.annotation.SmallTest;
@@ -44,9 +53,9 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import java.util.Locale;
/** Unit tests for {@link SoftApManager}. */
@@ -57,28 +66,32 @@
private static final String DEFAULT_SSID = "DefaultTestSSID";
private static final String TEST_SSID = "TestSSID";
+ private static final String TEST_PASSWORD = "TestPassword";
private static final String TEST_COUNTRY_CODE = "TestCountry";
private static final Integer[] ALLOWED_2G_CHANNELS = {1, 2, 3, 4};
private static final String TEST_INTERFACE_NAME = "testif0";
+ private static final int TEST_NUM_CONNECTED_CLIENTS = 4;
private final ArrayList<Integer> mAllowed2GChannels =
new ArrayList<>(Arrays.asList(ALLOWED_2G_CHANNELS));
private final WifiConfiguration mDefaultApConfig = createDefaultApConfig();
+ @Mock Context mContext;
TestLooper mLooper;
@Mock WifiNative mWifiNative;
@Mock SoftApManager.Listener mListener;
@Mock InterfaceConfiguration mInterfaceConfiguration;
- @Mock IBinder mApInterfaceBinder;
@Mock IApInterface mApInterface;
@Mock INetworkManagementService mNmService;
@Mock WifiApConfigStore mWifiApConfigStore;
@Mock WifiMetrics mWifiMetrics;
- final ArgumentCaptor<DeathRecipient> mDeathListenerCaptor =
- ArgumentCaptor.forClass(DeathRecipient.class);
+ final ArgumentCaptor<WifiNative.WificondDeathEventHandler> mDeathListenerCaptor =
+ ArgumentCaptor.forClass(WifiNative.WificondDeathEventHandler.class);
final ArgumentCaptor<BaseNetworkObserver> mNetworkObserverCaptor =
ArgumentCaptor.forClass(BaseNetworkObserver.class);
+ final ArgumentCaptor<WifiNative.SoftApListener> mSoftApListenerCaptor =
+ ArgumentCaptor.forClass(WifiNative.SoftApListener.class);
SoftApManager mSoftApManager;
@@ -88,12 +101,9 @@
MockitoAnnotations.initMocks(this);
mLooper = new TestLooper();
- when(mApInterface.asBinder()).thenReturn(mApInterfaceBinder);
- when(mApInterface.startHostapd()).thenReturn(true);
- when(mApInterface.stopHostapd()).thenReturn(true);
- when(mApInterface.writeHostapdConfig(
- any(), anyBoolean(), anyInt(), anyInt(), any())).thenReturn(true);
- when(mApInterface.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
+ when(mWifiNative.startSoftAp(any(), any())).thenReturn(true);
+ when(mWifiNative.stopSoftAp()).thenReturn(true);
+ when(mWifiNative.registerWificondDeathHandler(any())).thenReturn(true);
}
private WifiConfiguration createDefaultApConfig() {
@@ -102,18 +112,17 @@
return defaultConfig;
}
- private SoftApManager createSoftApManager(WifiConfiguration config) throws Exception {
- when(mApInterface.asBinder()).thenReturn(mApInterfaceBinder);
- when(mApInterface.startHostapd()).thenReturn(true);
- when(mApInterface.stopHostapd()).thenReturn(true);
- if (config == null) {
+ private SoftApManager createSoftApManager(SoftApModeConfiguration config) throws Exception {
+ if (config.getWifiConfiguration() == null) {
when(mWifiApConfigStore.getApConfiguration()).thenReturn(mDefaultApConfig);
}
- SoftApManager newSoftApManager = new SoftApManager(mLooper.getLooper(),
+ SoftApManager newSoftApManager = new SoftApManager(mContext,
+ mLooper.getLooper(),
mWifiNative,
TEST_COUNTRY_CODE,
mListener,
mApInterface,
+ TEST_INTERFACE_NAME,
mNmService,
mWifiApConfigStore,
config,
@@ -125,7 +134,9 @@
/** Verifies startSoftAp will use default config if AP configuration is not provided. */
@Test
public void startSoftApWithoutConfig() throws Exception {
- startSoftApAndVerifyEnabled(null);
+ SoftApModeConfiguration apConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null);
+ startSoftApAndVerifyEnabled(apConfig);
}
/** Verifies startSoftAp will use provided config and start AP. */
@@ -134,10 +145,11 @@
WifiConfiguration config = new WifiConfiguration();
config.apBand = WifiConfiguration.AP_BAND_2GHZ;
config.SSID = TEST_SSID;
- startSoftApAndVerifyEnabled(config);
+ SoftApModeConfiguration apConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config);
+ startSoftApAndVerifyEnabled(apConfig);
}
-
/**
* Verifies startSoftAp will start with the hiddenSSID param set when it is set to true in the
* supplied config.
@@ -148,101 +160,378 @@
config.apBand = WifiConfiguration.AP_BAND_2GHZ;
config.SSID = TEST_SSID;
config.hiddenSSID = true;
- startSoftApAndVerifyEnabled(config);
+ SoftApModeConfiguration apConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config);
+ startSoftApAndVerifyEnabled(apConfig);
+ }
+
+ /**
+ * Verifies startSoftAp will start with the password param set in the
+ * supplied config.
+ */
+ @Test
+ public void startSoftApWithPassphraseInConfig() throws Exception {
+ WifiConfiguration config = new WifiConfiguration();
+ config.apBand = WifiConfiguration.AP_BAND_5GHZ;
+ config.SSID = TEST_SSID;
+ config.allowedKeyManagement.set(WPA_PSK);
+ config.preSharedKey = TEST_PASSWORD;
+ SoftApModeConfiguration apConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config);
+ startSoftApAndVerifyEnabled(apConfig);
}
/** Tests softap startup if default config fails to load. **/
@Test
public void startSoftApDefaultConfigFailedToLoad() throws Exception {
- when(mApInterface.asBinder()).thenReturn(mApInterfaceBinder);
- when(mApInterface.startHostapd()).thenReturn(true);
- when(mApInterface.stopHostapd()).thenReturn(true);
when(mWifiApConfigStore.getApConfiguration()).thenReturn(null);
- SoftApManager newSoftApManager = new SoftApManager(mLooper.getLooper(),
+ SoftApModeConfiguration nullApConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null);
+ SoftApManager newSoftApManager = new SoftApManager(mContext,
+ mLooper.getLooper(),
mWifiNative,
TEST_COUNTRY_CODE,
mListener,
mApInterface,
+ TEST_INTERFACE_NAME,
mNmService,
mWifiApConfigStore,
- null,
+ nullApConfig,
mWifiMetrics);
mLooper.dispatchAll();
newSoftApManager.start();
mLooper.dispatchAll();
verify(mListener).onStateChanged(WifiManager.WIFI_AP_STATE_FAILED,
WifiManager.SAP_START_FAILURE_GENERAL);
+ ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mContext, times(2)).sendStickyBroadcastAsUser(intentCaptor.capture(),
+ eq(UserHandle.ALL));
+
+ List<Intent> capturedIntents = intentCaptor.getAllValues();
+ checkApStateChangedBroadcast(capturedIntents.get(0), WIFI_AP_STATE_ENABLING,
+ WIFI_AP_STATE_DISABLED, HOTSPOT_NO_ERROR, TEST_INTERFACE_NAME,
+ nullApConfig.getTargetMode());
+ checkApStateChangedBroadcast(capturedIntents.get(1), WIFI_AP_STATE_FAILED,
+ WIFI_AP_STATE_ENABLING, WifiManager.SAP_START_FAILURE_GENERAL, TEST_INTERFACE_NAME,
+ nullApConfig.getTargetMode());
+ }
+
+ /**
+ * Tests that the generic error is propagated and properly reported when starting softap and the
+ * specified channel cannot be used.
+ */
+ @Test
+ public void startSoftApFailGeneralErrorForConfigChannel() throws Exception {
+ WifiConfiguration config = new WifiConfiguration();
+ config.apBand = WifiConfiguration.AP_BAND_5GHZ;
+ config.SSID = TEST_SSID;
+ SoftApModeConfiguration softApConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config);
+
+ when(mWifiNative.isHalStarted()).thenReturn(true);
+
+ SoftApManager newSoftApManager = new SoftApManager(mContext,
+ mLooper.getLooper(),
+ mWifiNative,
+ null,
+ mListener,
+ mApInterface,
+ TEST_INTERFACE_NAME,
+ mNmService,
+ mWifiApConfigStore,
+ softApConfig,
+ mWifiMetrics);
+ mLooper.dispatchAll();
+ newSoftApManager.start();
+ mLooper.dispatchAll();
+
+ ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mContext, times(2)).sendStickyBroadcastAsUser(intentCaptor.capture(),
+ eq(UserHandle.ALL));
+
+ List<Intent> capturedIntents = intentCaptor.getAllValues();
+ checkApStateChangedBroadcast(capturedIntents.get(0), WIFI_AP_STATE_ENABLING,
+ WIFI_AP_STATE_DISABLED, HOTSPOT_NO_ERROR, TEST_INTERFACE_NAME,
+ softApConfig.getTargetMode());
+ checkApStateChangedBroadcast(capturedIntents.get(1), WIFI_AP_STATE_FAILED,
+ WIFI_AP_STATE_ENABLING, WifiManager.SAP_START_FAILURE_GENERAL, TEST_INTERFACE_NAME,
+ softApConfig.getTargetMode());
+ }
+
+ /**
+ * Tests that the NO_CHANNEL error is propagated and properly reported when starting softap and
+ * a valid channel cannot be determined.
+ */
+ @Test
+ public void startSoftApFailNoChannel() throws Exception {
+ WifiConfiguration config = new WifiConfiguration();
+ config.apBand = -2;
+ config.apChannel = 0;
+ config.SSID = TEST_SSID;
+ SoftApModeConfiguration softApConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config);
+
+ when(mWifiNative.isHalStarted()).thenReturn(true);
+
+ SoftApManager newSoftApManager = new SoftApManager(mContext,
+ mLooper.getLooper(),
+ mWifiNative,
+ TEST_COUNTRY_CODE,
+ mListener,
+ mApInterface,
+ TEST_INTERFACE_NAME,
+ mNmService,
+ mWifiApConfigStore,
+ softApConfig,
+ mWifiMetrics);
+ mLooper.dispatchAll();
+ newSoftApManager.start();
+ mLooper.dispatchAll();
+
+ ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mContext, times(2)).sendStickyBroadcastAsUser(intentCaptor.capture(),
+ eq(UserHandle.ALL));
+
+ List<Intent> capturedIntents = intentCaptor.getAllValues();
+ checkApStateChangedBroadcast(capturedIntents.get(0), WIFI_AP_STATE_ENABLING,
+ WIFI_AP_STATE_DISABLED, HOTSPOT_NO_ERROR, TEST_INTERFACE_NAME,
+ softApConfig.getTargetMode());
+ checkApStateChangedBroadcast(capturedIntents.get(1), WIFI_AP_STATE_FAILED,
+ WIFI_AP_STATE_ENABLING, WifiManager.SAP_START_FAILURE_NO_CHANNEL,
+ TEST_INTERFACE_NAME, softApConfig.getTargetMode());
+ }
+
+ /**
+ * Tests startup when Ap Interface fails to start successfully.
+ */
+ @Test
+ public void startSoftApApInterfaceFailedToStart() throws Exception {
+ when(mWifiNative.startSoftAp(any(), any())).thenReturn(false);
+ SoftApModeConfiguration softApModeConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, mDefaultApConfig);
+ SoftApManager newSoftApManager = new SoftApManager(mContext,
+ mLooper.getLooper(),
+ mWifiNative,
+ TEST_COUNTRY_CODE,
+ mListener,
+ mApInterface,
+ TEST_INTERFACE_NAME,
+ mNmService,
+ mWifiApConfigStore,
+ softApModeConfig,
+ mWifiMetrics);
+
+ mLooper.dispatchAll();
+ newSoftApManager.start();
+ mLooper.dispatchAll();
+ verify(mListener).onStateChanged(WifiManager.WIFI_AP_STATE_FAILED,
+ WifiManager.SAP_START_FAILURE_GENERAL);
}
- /** Tests the handling of stop command when soft AP is not started. */
+ /**
+ * Tests the handling of stop command when soft AP is not started.
+ */
@Test
public void stopWhenNotStarted() throws Exception {
- mSoftApManager = createSoftApManager(null);
+ mSoftApManager = createSoftApManager(
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null));
mSoftApManager.stop();
mLooper.dispatchAll();
/* Verify no state changes. */
verify(mListener, never()).onStateChanged(anyInt(), anyInt());
+ verify(mContext, never()).sendStickyBroadcastAsUser(any(), any());
}
- /** Tests the handling of stop command when soft AP is started. */
+ /**
+ * Tests the handling of stop command when soft AP is started.
+ */
@Test
public void stopWhenStarted() throws Exception {
- startSoftApAndVerifyEnabled(null);
+ SoftApModeConfiguration softApModeConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null);
+ startSoftApAndVerifyEnabled(softApModeConfig);
+
+ // reset to clear verified Intents for ap state change updates
+ reset(mContext);
InOrder order = inOrder(mListener);
mSoftApManager.stop();
mLooper.dispatchAll();
- verify(mApInterface).stopHostapd();
+ verify(mWifiNative).stopSoftAp();
order.verify(mListener).onStateChanged(WifiManager.WIFI_AP_STATE_DISABLING, 0);
order.verify(mListener).onStateChanged(WifiManager.WIFI_AP_STATE_DISABLED, 0);
+ ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mContext, times(2)).sendStickyBroadcastAsUser(intentCaptor.capture(),
+ eq(UserHandle.ALL));
+
+ List<Intent> capturedIntents = intentCaptor.getAllValues();
+ checkApStateChangedBroadcast(capturedIntents.get(0), WIFI_AP_STATE_DISABLING,
+ WIFI_AP_STATE_ENABLED, HOTSPOT_NO_ERROR, TEST_INTERFACE_NAME,
+ softApModeConfig.getTargetMode());
+ checkApStateChangedBroadcast(capturedIntents.get(1), WIFI_AP_STATE_DISABLED,
+ WIFI_AP_STATE_DISABLING, HOTSPOT_NO_ERROR, TEST_INTERFACE_NAME,
+ softApModeConfig.getTargetMode());
}
+ /**
+ * Verify that SoftAp mode shuts down if wificond dies.
+ */
@Test
public void handlesWificondInterfaceDeath() throws Exception {
- startSoftApAndVerifyEnabled(null);
+ SoftApModeConfiguration softApModeConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null);
+ startSoftApAndVerifyEnabled(softApModeConfig);
- mDeathListenerCaptor.getValue().binderDied();
+ // reset to clear verified Intents for ap state change updates
+ reset(mContext);
+
+ mDeathListenerCaptor.getValue().onDeath();
mLooper.dispatchAll();
InOrder order = inOrder(mListener);
order.verify(mListener).onStateChanged(WifiManager.WIFI_AP_STATE_DISABLING, 0);
order.verify(mListener).onStateChanged(WifiManager.WIFI_AP_STATE_FAILED,
WifiManager.SAP_START_FAILURE_GENERAL);
+ ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mContext, times(2)).sendStickyBroadcastAsUser(intentCaptor.capture(),
+ eq(UserHandle.ALL));
+
+ List<Intent> capturedIntents = intentCaptor.getAllValues();
+ checkApStateChangedBroadcast(capturedIntents.get(0), WIFI_AP_STATE_DISABLING,
+ WIFI_AP_STATE_ENABLED, HOTSPOT_NO_ERROR, TEST_INTERFACE_NAME,
+ softApModeConfig.getTargetMode());
+ checkApStateChangedBroadcast(capturedIntents.get(1), WIFI_AP_STATE_FAILED,
+ WIFI_AP_STATE_DISABLING, WifiManager.SAP_START_FAILURE_GENERAL, TEST_INTERFACE_NAME,
+ softApModeConfig.getTargetMode());
+ }
+
+ @Test
+ public void updatesNumAssociatedStations() throws Exception {
+ SoftApModeConfiguration apConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null);
+ startSoftApAndVerifyEnabled(apConfig);
+
+ mSoftApListenerCaptor.getValue().onNumAssociatedStationsChanged(
+ TEST_NUM_CONNECTED_CLIENTS);
+ mLooper.dispatchAll();
+ assertEquals(TEST_NUM_CONNECTED_CLIENTS, mSoftApManager.getNumAssociatedStations());
+ verify(mWifiMetrics).addSoftApNumAssociatedStationsChangedEvent(TEST_NUM_CONNECTED_CLIENTS,
+ apConfig.getTargetMode());
+ }
+
+ @Test
+ public void handlesNumAssociatedStationsWhenNotStarted() throws Exception {
+ SoftApModeConfiguration apConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null);
+ startSoftApAndVerifyEnabled(apConfig);
+ mSoftApManager.stop();
+ mLooper.dispatchAll();
+
+ mSoftApListenerCaptor.getValue().onNumAssociatedStationsChanged(
+ TEST_NUM_CONNECTED_CLIENTS);
+ mLooper.dispatchAll();
+ /* Verify numAssociatedStations is not updated when soft AP is not started */
+ assertEquals(0, mSoftApManager.getNumAssociatedStations());
+ verify(mWifiMetrics).addSoftApUpChangedEvent(false, apConfig.getTargetMode());
+ verify(mWifiMetrics, never()).addSoftApNumAssociatedStationsChangedEvent(
+ TEST_NUM_CONNECTED_CLIENTS, apConfig.getTargetMode());
+ }
+
+ @Test
+ public void handlesInvalidNumAssociatedStations() throws Exception {
+ SoftApModeConfiguration apConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null);
+ startSoftApAndVerifyEnabled(apConfig);
+
+ mSoftApListenerCaptor.getValue().onNumAssociatedStationsChanged(
+ TEST_NUM_CONNECTED_CLIENTS);
+ /* Invalid values should be ignored */
+ mSoftApListenerCaptor.getValue().onNumAssociatedStationsChanged(-1);
+ mLooper.dispatchAll();
+ assertEquals(TEST_NUM_CONNECTED_CLIENTS, mSoftApManager.getNumAssociatedStations());
+ verify(mWifiMetrics, times(1)).addSoftApNumAssociatedStationsChangedEvent(
+ TEST_NUM_CONNECTED_CLIENTS, apConfig.getTargetMode());
+ }
+
+ @Test
+ public void resetsNumAssociatedStationsWhenStopped() throws Exception {
+ SoftApModeConfiguration apConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null);
+ startSoftApAndVerifyEnabled(apConfig);
+
+ mSoftApListenerCaptor.getValue().onNumAssociatedStationsChanged(
+ TEST_NUM_CONNECTED_CLIENTS);
+ mSoftApManager.stop();
+ mLooper.dispatchAll();
+ assertEquals(0, mSoftApManager.getNumAssociatedStations());
+ verify(mWifiMetrics).addSoftApUpChangedEvent(false, apConfig.getTargetMode());
+ }
+
+ @Test
+ public void resetsNumAssociatedStationsOnFailure() throws Exception {
+ SoftApModeConfiguration apConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null);
+ startSoftApAndVerifyEnabled(apConfig);
+
+ mSoftApListenerCaptor.getValue().onNumAssociatedStationsChanged(
+ TEST_NUM_CONNECTED_CLIENTS);
+ /* Force soft AP to fail */
+ mDeathListenerCaptor.getValue().onDeath();
+ mLooper.dispatchAll();
+ verify(mListener).onStateChanged(WifiManager.WIFI_AP_STATE_FAILED,
+ WifiManager.SAP_START_FAILURE_GENERAL);
+
+ assertEquals(0, mSoftApManager.getNumAssociatedStations());
+ verify(mWifiMetrics).addSoftApUpChangedEvent(false, apConfig.getTargetMode());
}
/** Starts soft AP and verifies that it is enabled successfully. */
- protected void startSoftApAndVerifyEnabled(WifiConfiguration config) throws Exception {
- String expectedSSID;
- boolean expectedHiddenSsid;
- InOrder order = inOrder(mListener, mApInterfaceBinder, mApInterface, mNmService);
+ protected void startSoftApAndVerifyEnabled(
+ SoftApModeConfiguration softApConfig) throws Exception {
+ WifiConfiguration expectedConfig;
+ InOrder order =
+ inOrder(mListener, mApInterface, mWifiNative, mNmService);
when(mWifiNative.isHalStarted()).thenReturn(false);
when(mWifiNative.setCountryCodeHal(TEST_COUNTRY_CODE.toUpperCase(Locale.ROOT)))
.thenReturn(true);
- mSoftApManager = createSoftApManager(config);
+ mSoftApManager = createSoftApManager(softApConfig);
+ WifiConfiguration config = softApConfig.getWifiConfiguration();
if (config == null) {
when(mWifiApConfigStore.getApConfiguration()).thenReturn(mDefaultApConfig);
- expectedSSID = mDefaultApConfig.SSID;
- expectedHiddenSsid = mDefaultApConfig.hiddenSSID;
+ expectedConfig = new WifiConfiguration(mDefaultApConfig);
} else {
- expectedSSID = config.SSID;
- expectedHiddenSsid = config.hiddenSSID;
+ expectedConfig = new WifiConfiguration(config);
}
+ ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+
mSoftApManager.start();
mLooper.dispatchAll();
order.verify(mListener).onStateChanged(WifiManager.WIFI_AP_STATE_ENABLING, 0);
- order.verify(mApInterfaceBinder).linkToDeath(mDeathListenerCaptor.capture(), eq(0));
+ order.verify(mWifiNative).registerWificondDeathHandler(mDeathListenerCaptor.capture());
order.verify(mNmService).registerObserver(mNetworkObserverCaptor.capture());
- order.verify(mApInterface).writeHostapdConfig(
- eq(expectedSSID.getBytes(StandardCharsets.UTF_8)), eq(expectedHiddenSsid),
- anyInt(), anyInt(), any());
- order.verify(mApInterface).startHostapd();
+ ArgumentCaptor<WifiConfiguration> configCaptor =
+ ArgumentCaptor.forClass(WifiConfiguration.class);
+ order.verify(mWifiNative).startSoftAp(
+ configCaptor.capture(), mSoftApListenerCaptor.capture());
+ WifiConfigurationTestUtil.assertConfigurationEqual(expectedConfig, configCaptor.getValue());
mNetworkObserverCaptor.getValue().interfaceLinkStateChanged(TEST_INTERFACE_NAME, true);
mLooper.dispatchAll();
order.verify(mListener).onStateChanged(WifiManager.WIFI_AP_STATE_ENABLED, 0);
+ verify(mContext, times(2)).sendStickyBroadcastAsUser(intentCaptor.capture(),
+ eq(UserHandle.ALL));
+ List<Intent> capturedIntents = intentCaptor.getAllValues();
+ checkApStateChangedBroadcast(capturedIntents.get(0), WIFI_AP_STATE_ENABLING,
+ WIFI_AP_STATE_DISABLED, HOTSPOT_NO_ERROR, TEST_INTERFACE_NAME,
+ softApConfig.getTargetMode());
+ checkApStateChangedBroadcast(capturedIntents.get(1), WIFI_AP_STATE_ENABLED,
+ WIFI_AP_STATE_ENABLING, HOTSPOT_NO_ERROR, TEST_INTERFACE_NAME,
+ softApConfig.getTargetMode());
+ assertEquals(0, mSoftApManager.getNumAssociatedStations());
+ verify(mWifiMetrics).addSoftApUpChangedEvent(true, softApConfig.mTargetMode);
}
/** Verifies that soft AP was not disabled. */
@@ -250,4 +539,19 @@
verify(mListener, never()).onStateChanged(WifiManager.WIFI_AP_STATE_DISABLING, 0);
verify(mListener, never()).onStateChanged(WifiManager.WIFI_AP_STATE_DISABLED, 0);
}
+
+ private void checkApStateChangedBroadcast(Intent intent, int expectedCurrentState,
+ int expectedPrevState, int expectedErrorCode,
+ String expectedIfaceName, int expectedMode) {
+ int currentState = intent.getIntExtra(EXTRA_WIFI_AP_STATE, WIFI_AP_STATE_DISABLED);
+ int prevState = intent.getIntExtra(EXTRA_PREVIOUS_WIFI_AP_STATE, WIFI_AP_STATE_DISABLED);
+ int errorCode = intent.getIntExtra(EXTRA_WIFI_AP_FAILURE_REASON, HOTSPOT_NO_ERROR);
+ String ifaceName = intent.getStringExtra(EXTRA_WIFI_AP_INTERFACE_NAME);
+ int mode = intent.getIntExtra(EXTRA_WIFI_AP_MODE, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
+ assertEquals(expectedCurrentState, currentState);
+ assertEquals(expectedPrevState, prevState);
+ assertEquals(expectedErrorCode, errorCode);
+ assertEquals(expectedIfaceName, ifaceName);
+ assertEquals(expectedMode, mode);
+ }
}
diff --git a/tests/wifitests/src/com/android/server/wifi/SupplicantStaIfaceHalTest.java b/tests/wifitests/src/com/android/server/wifi/SupplicantStaIfaceHalTest.java
index 2deef52..0303d9a 100644
--- a/tests/wifitests/src/com/android/server/wifi/SupplicantStaIfaceHalTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/SupplicantStaIfaceHalTest.java
@@ -23,15 +23,7 @@
import static org.mockito.Matchers.anyShort;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.*;
import android.app.test.MockAnswerUtil;
import android.content.Context;
@@ -54,6 +46,7 @@
import android.net.wifi.WifiSsid;
import android.os.IHwBinder;
import android.os.RemoteException;
+import android.text.TextUtils;
import android.util.SparseArray;
import com.android.server.wifi.hotspot2.AnqpEvent;
@@ -61,6 +54,8 @@
import com.android.server.wifi.hotspot2.WnmData;
import com.android.server.wifi.util.NativeUtil;
+import libcore.util.NonNull;
+
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
@@ -90,7 +85,8 @@
private static final String SUPPLICANT_SSID = NETWORK_ID_TO_SSID.get(SUPPLICANT_NETWORK_ID);
private static final int ROAM_NETWORK_ID = 4;
private static final String BSSID = "fa:45:23:23:12:12";
- private static final String WLAN_IFACE_NAME = "wlan0";
+ private static final String WLAN0_IFACE_NAME = "wlan0";
+ private static final String WLAN1_IFACE_NAME = "wlan1";
private static final String P2P_IFACE_NAME = "p2p0";
private static final String ICON_FILE_NAME = "blahblah";
private static final int ICON_FILE_SIZE = 72;
@@ -103,9 +99,11 @@
@Mock Context mContext;
@Mock WifiMonitor mWifiMonitor;
@Mock SupplicantStaNetworkHal mSupplicantStaNetworkMock;
+ @Mock WifiNative.SupplicantDeathEventHandler mSupplicantHalDeathHandler;
SupplicantStatus mStatusSuccess;
SupplicantStatus mStatusFailure;
- ISupplicant.IfaceInfo mStaIface;
+ ISupplicant.IfaceInfo mStaIface0;
+ ISupplicant.IfaceInfo mStaIface1;
ISupplicant.IfaceInfo mP2pIface;
ArrayList<ISupplicant.IfaceInfo> mIfaceInfoList;
ISupplicantStaIfaceCallback mISupplicantStaIfaceCallback;
@@ -142,6 +140,7 @@
@Override
protected SupplicantStaNetworkHal getStaNetworkMockable(
+ @NonNull String ifaceName,
ISupplicantStaNetwork iSupplicantStaNetwork) {
return mSupplicantStaNetworkMock;
}
@@ -152,11 +151,13 @@
MockitoAnnotations.initMocks(this);
mStatusSuccess = createSupplicantStatus(SupplicantStatusCode.SUCCESS);
mStatusFailure = createSupplicantStatus(SupplicantStatusCode.FAILURE_UNKNOWN);
- mStaIface = createIfaceInfo(IfaceType.STA, WLAN_IFACE_NAME);
+ mStaIface0 = createIfaceInfo(IfaceType.STA, WLAN0_IFACE_NAME);
+ mStaIface1 = createIfaceInfo(IfaceType.STA, WLAN1_IFACE_NAME);
mP2pIface = createIfaceInfo(IfaceType.P2P, P2P_IFACE_NAME);
mIfaceInfoList = new ArrayList<>();
- mIfaceInfoList.add(mStaIface);
+ mIfaceInfoList.add(mStaIface0);
+ mIfaceInfoList.add(mStaIface1);
mIfaceInfoList.add(mP2pIface);
when(mServiceManagerMock.linkToDeath(any(IHwBinder.DeathRecipient.class),
@@ -215,6 +216,50 @@
executeAndValidateInitializationSequence(false, false, false, true);
}
+
+ /**
+ * Sunny day scenario for SupplicantStaIfaceHal initialization
+ * Asserts successful initialization of second interface
+ */
+ @Test
+ public void testSetupTwoInterfaces() throws Exception {
+ executeAndValidateInitializationSequence(false, false, false, false);
+ assertTrue(mDut.setupIface(WLAN1_IFACE_NAME));
+ }
+
+ /**
+ * Ensures that we do not allow operations on an interface until it's setup.
+ */
+ @Test
+ public void testEnsureOperationFailsUntilSetupInterfaces() throws Exception {
+ executeAndValidateInitializationSequence(false, false, false, false);
+
+ // Ensure that the cancel wps operation is failed because wlan1 interface is not yet setup.
+ assertFalse(mDut.cancelWps(WLAN1_IFACE_NAME));
+ verify(mISupplicantStaIfaceMock, never()).cancelWps();
+
+ // Now setup the wlan1 interface and Ensure that the cancel wps operation is successful.
+ assertTrue(mDut.setupIface(WLAN1_IFACE_NAME));
+ when(mISupplicantStaIfaceMock.cancelWps()).thenReturn(mStatusSuccess);
+ assertTrue(mDut.cancelWps(WLAN1_IFACE_NAME));
+ verify(mISupplicantStaIfaceMock).cancelWps();
+ }
+
+ /**
+ * Sunny day scenario for SupplicantStaIfaceHal interface teardown.
+ * Asserts successful initialization of second interface
+ */
+ @Test
+ public void testTeardownTwoInterfaces() throws Exception {
+ testSetupTwoInterfaces();
+ assertTrue(mDut.teardownIface(WLAN0_IFACE_NAME));
+ assertTrue(mDut.teardownIface(WLAN1_IFACE_NAME));
+
+ // Ensure that the cancel wps operation is failed because there are no interfaces setup.
+ assertFalse(mDut.cancelWps(WLAN0_IFACE_NAME));
+ verify(mISupplicantStaIfaceMock, never()).cancelWps();
+ }
+
/**
* Tests the loading of networks using {@link SupplicantStaNetworkHal}.
* Fills up only the SSID field of configs and uses it as a configKey as well.
@@ -250,7 +295,7 @@
Map<String, WifiConfiguration> configs = new HashMap<>();
SparseArray<Map<String, String>> extras = new SparseArray<>();
- assertTrue(mDut.loadNetworks(configs, extras));
+ assertTrue(mDut.loadNetworks(WLAN0_IFACE_NAME, configs, extras));
assertEquals(3, configs.size());
assertEquals(3, extras.size());
@@ -316,7 +361,7 @@
Map<String, WifiConfiguration> configs = new HashMap<>();
SparseArray<Map<String, String>> extras = new SparseArray<>();
- assertTrue(mDut.loadNetworks(configs, extras));
+ assertTrue(mDut.loadNetworks(WLAN0_IFACE_NAME, configs, extras));
assertEquals(2, configs.size());
assertEquals(2, extras.size());
@@ -355,7 +400,7 @@
Map<String, WifiConfiguration> configs = new HashMap<>();
SparseArray<Map<String, String>> extras = new SparseArray<>();
- assertFalse(mDut.loadNetworks(configs, extras));
+ assertFalse(mDut.loadNetworks(WLAN0_IFACE_NAME, configs, extras));
}
/**
@@ -380,7 +425,7 @@
Map<String, WifiConfiguration> configs = new HashMap<>();
SparseArray<Map<String, String>> extras = new SparseArray<>();
- assertFalse(mDut.loadNetworks(configs, extras));
+ assertFalse(mDut.loadNetworks(WLAN0_IFACE_NAME, configs, extras));
}
/**
@@ -411,7 +456,7 @@
Map<String, WifiConfiguration> configs = new HashMap<>();
SparseArray<Map<String, String>> extras = new SparseArray<>();
- assertTrue(mDut.loadNetworks(configs, extras));
+ assertTrue(mDut.loadNetworks(WLAN0_IFACE_NAME, configs, extras));
assertTrue(configs.isEmpty());
}
@@ -444,7 +489,7 @@
Map<String, WifiConfiguration> configs = new HashMap<>();
SparseArray<Map<String, String>> extras = new SparseArray<>();
- assertTrue(mDut.loadNetworks(configs, extras));
+ assertTrue(mDut.loadNetworks(WLAN0_IFACE_NAME, configs, extras));
assertTrue(configs.isEmpty());
}
@@ -468,7 +513,7 @@
setupMocksForConnectSequence(true /*haveExistingNetwork*/);
// Make this network different by changing SSID.
config.SSID = "AnDifferentSSID";
- assertTrue(mDut.connectToNetwork(config));
+ assertTrue(mDut.connectToNetwork(WLAN0_IFACE_NAME, config));
verify(mISupplicantStaIfaceMock).removeNetwork(SUPPLICANT_NETWORK_ID);
verify(mISupplicantStaIfaceMock)
.addNetwork(any(ISupplicantStaIface.addNetworkCallback.class));
@@ -482,7 +527,29 @@
// Reset mocks for mISupplicantStaIfaceMock because we finished the first connection.
reset(mISupplicantStaIfaceMock);
setupMocksForConnectSequence(true /*haveExistingNetwork*/);
- assertTrue(mDut.connectToNetwork(config));
+ assertTrue(mDut.connectToNetwork(WLAN0_IFACE_NAME, config));
+ verify(mISupplicantStaIfaceMock, never()).removeNetwork(anyInt());
+ verify(mISupplicantStaIfaceMock, never())
+ .addNetwork(any(ISupplicantStaIface.addNetworkCallback.class));
+ }
+
+ @Test
+ public void connectToNetworkWithSameNetworkButDifferentBssidUpdatesNetworkFromSupplicant()
+ throws Exception {
+ executeAndValidateInitializationSequence();
+ WifiConfiguration config = executeAndValidateConnectSequence(SUPPLICANT_NETWORK_ID, false);
+ String testBssid = "11:22:33:44:55:66";
+ when(mSupplicantStaNetworkMock.setBssid(eq(testBssid))).thenReturn(true);
+
+ // Reset mocks for mISupplicantStaIfaceMock because we finished the first connection.
+ reset(mISupplicantStaIfaceMock);
+ setupMocksForConnectSequence(true /*haveExistingNetwork*/);
+ // Change the BSSID and connect to the same network.
+ assertFalse(TextUtils.equals(
+ testBssid, config.getNetworkSelectionStatus().getNetworkSelectionBSSID()));
+ config.getNetworkSelectionStatus().setNetworkSelectionBSSID(testBssid);
+ assertTrue(mDut.connectToNetwork(WLAN0_IFACE_NAME, config));
+ verify(mSupplicantStaNetworkMock).setBssid(eq(testBssid));
verify(mISupplicantStaIfaceMock, never()).removeNetwork(anyInt());
verify(mISupplicantStaIfaceMock, never())
.addNetwork(any(ISupplicantStaIface.addNetworkCallback.class));
@@ -503,7 +570,7 @@
}).when(mISupplicantStaIfaceMock).addNetwork(
any(ISupplicantStaIface.addNetworkCallback.class));
- assertFalse(mDut.connectToNetwork(createTestWifiConfiguration()));
+ assertFalse(mDut.connectToNetwork(WLAN0_IFACE_NAME, createTestWifiConfiguration()));
}
/**
@@ -517,7 +584,7 @@
when(mSupplicantStaNetworkMock.saveWifiConfiguration(any(WifiConfiguration.class)))
.thenReturn(false);
- assertFalse(mDut.connectToNetwork(createTestWifiConfiguration()));
+ assertFalse(mDut.connectToNetwork(WLAN0_IFACE_NAME, createTestWifiConfiguration()));
// We should have removed the existing network once before connection and once more
// on failure to save network configuration.
verify(mISupplicantStaIfaceMock, times(2)).removeNetwork(anyInt());
@@ -535,7 +602,7 @@
.when(mSupplicantStaNetworkMock).saveWifiConfiguration(
any(WifiConfiguration.class));
- assertFalse(mDut.connectToNetwork(createTestWifiConfiguration()));
+ assertFalse(mDut.connectToNetwork(WLAN0_IFACE_NAME, createTestWifiConfiguration()));
// We should have removed the existing network once before connection and once more
// on failure to save network configuration.
verify(mISupplicantStaIfaceMock, times(2)).removeNetwork(anyInt());
@@ -551,7 +618,7 @@
when(mSupplicantStaNetworkMock.select()).thenReturn(false);
- assertFalse(mDut.connectToNetwork(createTestWifiConfiguration()));
+ assertFalse(mDut.connectToNetwork(WLAN0_IFACE_NAME, createTestWifiConfiguration()));
}
/**
@@ -561,7 +628,7 @@
public void testRoamToSameNetwork() throws Exception {
executeAndValidateInitializationSequence();
executeAndValidateRoamSequence(true);
- assertTrue(mDut.connectToNetwork(createTestWifiConfiguration()));
+ assertTrue(mDut.connectToNetwork(WLAN0_IFACE_NAME, createTestWifiConfiguration()));
}
/**
@@ -586,7 +653,7 @@
WifiConfiguration roamingConfig = new WifiConfiguration();
roamingConfig.networkId = connectedNetworkId;
roamingConfig.getNetworkSelectionStatus().setNetworkSelectionBSSID("45:34:23:23:ab:ed");
- assertFalse(mDut.roamToNetwork(roamingConfig));
+ assertFalse(mDut.roamToNetwork(WLAN0_IFACE_NAME, roamingConfig));
}
/**
@@ -608,7 +675,7 @@
}
}).when(mISupplicantStaIfaceMock).removeNetwork(anyInt());
- assertTrue(mDut.removeAllNetworks());
+ assertTrue(mDut.removeAllNetworks(WLAN0_IFACE_NAME));
verify(mISupplicantStaIfaceMock, times(NETWORK_ID_TO_SSID.size())).removeNetwork(anyInt());
}
@@ -624,13 +691,13 @@
// Connect to a network and verify current network is set.
executeAndValidateConnectSequence(4, false);
- assertTrue(mDut.setCurrentNetworkBssid(testBssid));
+ assertTrue(mDut.setCurrentNetworkBssid(WLAN0_IFACE_NAME, testBssid));
verify(mSupplicantStaNetworkMock).setBssid(eq(testBssid));
reset(mSupplicantStaNetworkMock);
// Remove all networks and verify current network info is resetted.
- assertTrue(mDut.removeAllNetworks());
- assertFalse(mDut.setCurrentNetworkBssid(testBssid));
+ assertTrue(mDut.removeAllNetworks(WLAN0_IFACE_NAME));
+ assertFalse(mDut.setCurrentNetworkBssid(WLAN0_IFACE_NAME, testBssid));
verify(mSupplicantStaNetworkMock, never()).setBssid(eq(testBssid));
}
@@ -653,7 +720,7 @@
WifiConfiguration roamingConfig = new WifiConfiguration();
roamingConfig.networkId = connectedNetworkId;
roamingConfig.getNetworkSelectionStatus().setNetworkSelectionBSSID("45:34:23:23:ab:ed");
- assertFalse(mDut.roamToNetwork(roamingConfig));
+ assertFalse(mDut.roamToNetwork(WLAN0_IFACE_NAME, roamingConfig));
}
/**
@@ -666,10 +733,10 @@
executeAndValidateInitializationSequence();
// Return null when not connected to the network.
- assertTrue(mDut.getCurrentNetworkWpsNfcConfigurationToken() == null);
+ assertTrue(mDut.getCurrentNetworkWpsNfcConfigurationToken(WLAN0_IFACE_NAME) == null);
verify(mSupplicantStaNetworkMock, never()).getWpsNfcConfigurationToken();
executeAndValidateConnectSequence(4, false);
- assertEquals(token, mDut.getCurrentNetworkWpsNfcConfigurationToken());
+ assertEquals(token, mDut.getCurrentNetworkWpsNfcConfigurationToken(WLAN0_IFACE_NAME));
verify(mSupplicantStaNetworkMock).getWpsNfcConfigurationToken();
}
@@ -683,10 +750,10 @@
executeAndValidateInitializationSequence();
// Fail when not connected to a network.
- assertFalse(mDut.setCurrentNetworkBssid(bssidStr));
+ assertFalse(mDut.setCurrentNetworkBssid(WLAN0_IFACE_NAME, bssidStr));
verify(mSupplicantStaNetworkMock, never()).setBssid(eq(bssidStr));
executeAndValidateConnectSequence(4, false);
- assertTrue(mDut.setCurrentNetworkBssid(bssidStr));
+ assertTrue(mDut.setCurrentNetworkBssid(WLAN0_IFACE_NAME, bssidStr));
verify(mSupplicantStaNetworkMock).setBssid(eq(bssidStr));
}
@@ -701,10 +768,10 @@
executeAndValidateInitializationSequence();
// Fail when not connected to a network.
- assertFalse(mDut.sendCurrentNetworkEapIdentityResponse(identity));
+ assertFalse(mDut.sendCurrentNetworkEapIdentityResponse(WLAN0_IFACE_NAME, identity));
verify(mSupplicantStaNetworkMock, never()).sendNetworkEapIdentityResponse(eq(identity));
executeAndValidateConnectSequence(4, false);
- assertTrue(mDut.sendCurrentNetworkEapIdentityResponse(identity));
+ assertTrue(mDut.sendCurrentNetworkEapIdentityResponse(WLAN0_IFACE_NAME, identity));
verify(mSupplicantStaNetworkMock).sendNetworkEapIdentityResponse(eq(identity));
}
@@ -719,10 +786,11 @@
executeAndValidateInitializationSequence();
// Return null when not connected to the network.
- assertEquals(null, mDut.getCurrentNetworkEapAnonymousIdentity());
+ assertEquals(null, mDut.getCurrentNetworkEapAnonymousIdentity(WLAN0_IFACE_NAME));
executeAndValidateConnectSequence(4, false);
// Return anonymous identity for the current network.
- assertEquals(anonymousIdentity, mDut.getCurrentNetworkEapAnonymousIdentity());
+ assertEquals(
+ anonymousIdentity, mDut.getCurrentNetworkEapAnonymousIdentity(WLAN0_IFACE_NAME));
}
/**
@@ -736,10 +804,10 @@
executeAndValidateInitializationSequence();
// Fail when not connected to a network.
- assertFalse(mDut.sendCurrentNetworkEapSimGsmAuthResponse(params));
+ assertFalse(mDut.sendCurrentNetworkEapSimGsmAuthResponse(WLAN0_IFACE_NAME, params));
verify(mSupplicantStaNetworkMock, never()).sendNetworkEapSimGsmAuthResponse(eq(params));
executeAndValidateConnectSequence(4, false);
- assertTrue(mDut.sendCurrentNetworkEapSimGsmAuthResponse(params));
+ assertTrue(mDut.sendCurrentNetworkEapSimGsmAuthResponse(WLAN0_IFACE_NAME, params));
verify(mSupplicantStaNetworkMock).sendNetworkEapSimGsmAuthResponse(eq(params));
}
@@ -754,10 +822,10 @@
executeAndValidateInitializationSequence();
// Fail when not connected to a network.
- assertFalse(mDut.sendCurrentNetworkEapSimUmtsAuthResponse(params));
+ assertFalse(mDut.sendCurrentNetworkEapSimUmtsAuthResponse(WLAN0_IFACE_NAME, params));
verify(mSupplicantStaNetworkMock, never()).sendNetworkEapSimUmtsAuthResponse(eq(params));
executeAndValidateConnectSequence(4, false);
- assertTrue(mDut.sendCurrentNetworkEapSimUmtsAuthResponse(params));
+ assertTrue(mDut.sendCurrentNetworkEapSimUmtsAuthResponse(WLAN0_IFACE_NAME, params));
verify(mSupplicantStaNetworkMock).sendNetworkEapSimUmtsAuthResponse(eq(params));
}
@@ -772,10 +840,10 @@
executeAndValidateInitializationSequence();
// Fail when not connected to a network.
- assertFalse(mDut.sendCurrentNetworkEapSimUmtsAutsResponse(params));
+ assertFalse(mDut.sendCurrentNetworkEapSimUmtsAutsResponse(WLAN0_IFACE_NAME, params));
verify(mSupplicantStaNetworkMock, never()).sendNetworkEapSimUmtsAutsResponse(eq(params));
executeAndValidateConnectSequence(4, false);
- assertTrue(mDut.sendCurrentNetworkEapSimUmtsAutsResponse(params));
+ assertTrue(mDut.sendCurrentNetworkEapSimUmtsAutsResponse(WLAN0_IFACE_NAME, params));
verify(mSupplicantStaNetworkMock).sendNetworkEapSimUmtsAutsResponse(eq(params));
}
@@ -794,13 +862,13 @@
executeAndValidateInitializationSequence();
// This should work.
- assertTrue(mDut.setWpsDeviceType(validDeviceTypeStr));
+ assertTrue(mDut.setWpsDeviceType(WLAN0_IFACE_NAME, validDeviceTypeStr));
verify(mISupplicantStaIfaceMock).setWpsDeviceType(eq(expectedDeviceType));
// This should not work
- assertFalse(mDut.setWpsDeviceType(invalidDeviceType1Str));
+ assertFalse(mDut.setWpsDeviceType(WLAN0_IFACE_NAME, invalidDeviceType1Str));
// This should not work
- assertFalse(mDut.setWpsDeviceType(invalidDeviceType2Str));
+ assertFalse(mDut.setWpsDeviceType(WLAN0_IFACE_NAME, invalidDeviceType2Str));
}
/**
@@ -817,12 +885,12 @@
executeAndValidateInitializationSequence();
// This should work.
- assertTrue(mDut.setWpsConfigMethods(validConfigMethodsStr));
+ assertTrue(mDut.setWpsConfigMethods(WLAN0_IFACE_NAME, validConfigMethodsStr));
verify(mISupplicantStaIfaceMock).setWpsConfigMethods(eq(expectedConfigMethods));
// This should throw an illegal argument exception.
try {
- assertFalse(mDut.setWpsConfigMethods(invalidConfigMethodsStr));
+ assertFalse(mDut.setWpsConfigMethods(WLAN0_IFACE_NAME, invalidConfigMethodsStr));
} catch (IllegalArgumentException e) {
return;
}
@@ -845,7 +913,8 @@
new ISupplicantStaIfaceCallback.Hs20AnqpData());
ArgumentCaptor<AnqpEvent> anqpEventCaptor = ArgumentCaptor.forClass(AnqpEvent.class);
- verify(mWifiMonitor).broadcastAnqpDoneEvent(eq(WLAN_IFACE_NAME), anqpEventCaptor.capture());
+ verify(mWifiMonitor).broadcastAnqpDoneEvent(
+ eq(WLAN0_IFACE_NAME), anqpEventCaptor.capture());
assertEquals(
ByteBufferReader.readInteger(
ByteBuffer.wrap(bssid), ByteOrder.BIG_ENDIAN, bssid.length),
@@ -867,7 +936,8 @@
bssid, ICON_FILE_NAME, NativeUtil.byteArrayToArrayList(iconData));
ArgumentCaptor<IconEvent> iconEventCaptor = ArgumentCaptor.forClass(IconEvent.class);
- verify(mWifiMonitor).broadcastIconDoneEvent(eq(WLAN_IFACE_NAME), iconEventCaptor.capture());
+ verify(mWifiMonitor).broadcastIconDoneEvent(
+ eq(WLAN0_IFACE_NAME), iconEventCaptor.capture());
assertEquals(
ByteBufferReader.readInteger(
ByteBuffer.wrap(bssid), ByteOrder.BIG_ENDIAN, bssid.length),
@@ -890,7 +960,7 @@
bssid, osuMethod, HS20_URL);
ArgumentCaptor<WnmData> wnmDataCaptor = ArgumentCaptor.forClass(WnmData.class);
- verify(mWifiMonitor).broadcastWnmEvent(eq(WLAN_IFACE_NAME), wnmDataCaptor.capture());
+ verify(mWifiMonitor).broadcastWnmEvent(eq(WLAN0_IFACE_NAME), wnmDataCaptor.capture());
assertEquals(
ByteBufferReader.readInteger(
ByteBuffer.wrap(bssid), ByteOrder.BIG_ENDIAN, bssid.length),
@@ -931,7 +1001,7 @@
// Can't compare WifiSsid instances because they lack an equals.
verify(mWifiMonitor).broadcastSupplicantStateChangeEvent(
- eq(WLAN_IFACE_NAME), eq(WifiConfiguration.INVALID_NETWORK_ID),
+ eq(WLAN0_IFACE_NAME), eq(WifiConfiguration.INVALID_NETWORK_ID),
any(WifiSsid.class), eq(BSSID), eq(SupplicantState.INACTIVE));
}
@@ -951,7 +1021,7 @@
NativeUtil.decodeSsid(SUPPLICANT_SSID));
verify(mWifiMonitor).broadcastSupplicantStateChangeEvent(
- eq(WLAN_IFACE_NAME), eq(frameworkNetworkId),
+ eq(WLAN0_IFACE_NAME), eq(frameworkNetworkId),
any(WifiSsid.class), eq(BSSID), eq(SupplicantState.ASSOCIATED));
}
@@ -972,9 +1042,9 @@
NativeUtil.decodeSsid(SUPPLICANT_SSID));
wifiMonitorInOrder.verify(mWifiMonitor).broadcastNetworkConnectionEvent(
- eq(WLAN_IFACE_NAME), eq(frameworkNetworkId), eq(BSSID));
+ eq(WLAN0_IFACE_NAME), eq(frameworkNetworkId), eq(BSSID));
wifiMonitorInOrder.verify(mWifiMonitor).broadcastSupplicantStateChangeEvent(
- eq(WLAN_IFACE_NAME), eq(frameworkNetworkId),
+ eq(WLAN0_IFACE_NAME), eq(frameworkNetworkId),
any(WifiSsid.class), eq(BSSID), eq(SupplicantState.COMPLETED));
}
@@ -990,12 +1060,12 @@
mISupplicantStaIfaceCallback.onDisconnected(
NativeUtil.macAddressToByteArray(BSSID), true, reasonCode);
verify(mWifiMonitor).broadcastNetworkDisconnectionEvent(
- eq(WLAN_IFACE_NAME), eq(1), eq(reasonCode), eq(BSSID));
+ eq(WLAN0_IFACE_NAME), eq(1), eq(reasonCode), eq(BSSID));
mISupplicantStaIfaceCallback.onDisconnected(
NativeUtil.macAddressToByteArray(BSSID), false, reasonCode);
verify(mWifiMonitor).broadcastNetworkDisconnectionEvent(
- eq(WLAN_IFACE_NAME), eq(0), eq(reasonCode), eq(BSSID));
+ eq(WLAN0_IFACE_NAME), eq(0), eq(reasonCode), eq(BSSID));
}
/**
@@ -1025,7 +1095,7 @@
mISupplicantStaIfaceCallback.onDisconnected(
NativeUtil.macAddressToByteArray(BSSID), false, reasonCode);
- verify(mWifiMonitor, times(2)).broadcastAuthenticationFailureEvent(eq(WLAN_IFACE_NAME),
+ verify(mWifiMonitor, times(2)).broadcastAuthenticationFailureEvent(eq(WLAN0_IFACE_NAME),
eq(WifiManager.ERROR_AUTH_FAILURE_WRONG_PSWD));
}
@@ -1040,7 +1110,7 @@
executeAndValidateInitializationSequence();
assertNotNull(mISupplicantStaIfaceCallback);
- int reasonCode = 17; // IEEE 802.11i WLAN_REASON_IE_IN_4WAY_DIFFERS
+ int reasonCode = ISupplicantStaIfaceCallback.ReasonCode.IE_IN_4WAY_DIFFERS;
mISupplicantStaIfaceCallback.onStateChanged(
ISupplicantStaIfaceCallback.State.FOURWAY_HANDSHAKE,
@@ -1052,6 +1122,20 @@
verify(mWifiMonitor, times(0)).broadcastAuthenticationFailureEvent(any(), anyInt());
}
+ /**
+ * Tests the handling of eap failure during disconnect.
+ */
+ @Test
+ public void testEapFailure() throws Exception {
+ executeAndValidateInitializationSequence();
+ assertNotNull(mISupplicantStaIfaceCallback);
+
+ int reasonCode = ISupplicantStaIfaceCallback.ReasonCode.IEEE_802_1X_AUTH_FAILED;
+ mISupplicantStaIfaceCallback.onDisconnected(
+ NativeUtil.macAddressToByteArray(BSSID), false, reasonCode);
+ verify(mWifiMonitor).broadcastAuthenticationFailureEvent(eq(WLAN0_IFACE_NAME),
+ eq(WifiManager.ERROR_AUTH_FAILURE_EAP_FAILURE));
+ }
/**
* Tests the handling of association rejection notification.
@@ -1065,7 +1149,7 @@
mISupplicantStaIfaceCallback.onAssociationRejected(
NativeUtil.macAddressToByteArray(BSSID), statusCode, false);
verify(mWifiMonitor).broadcastAssociationRejectionEvent(
- eq(WLAN_IFACE_NAME), eq(statusCode), eq(false), eq(BSSID));
+ eq(WLAN0_IFACE_NAME), eq(statusCode), eq(false), eq(BSSID));
}
/**
@@ -1078,7 +1162,7 @@
mISupplicantStaIfaceCallback.onAuthenticationTimeout(
NativeUtil.macAddressToByteArray(BSSID));
- verify(mWifiMonitor).broadcastAuthenticationFailureEvent(eq(WLAN_IFACE_NAME),
+ verify(mWifiMonitor).broadcastAuthenticationFailureEvent(eq(WLAN0_IFACE_NAME),
eq(WifiManager.ERROR_AUTH_FAILURE_TIMEOUT));
}
@@ -1092,20 +1176,22 @@
mISupplicantStaIfaceCallback.onBssidChanged(
BssidChangeReason.ASSOC_START, NativeUtil.macAddressToByteArray(BSSID));
- verify(mWifiMonitor).broadcastTargetBssidEvent(eq(WLAN_IFACE_NAME), eq(BSSID));
- verify(mWifiMonitor, never()).broadcastAssociatedBssidEvent(eq(WLAN_IFACE_NAME), eq(BSSID));
+ verify(mWifiMonitor).broadcastTargetBssidEvent(eq(WLAN0_IFACE_NAME), eq(BSSID));
+ verify(mWifiMonitor, never()).broadcastAssociatedBssidEvent(
+ eq(WLAN0_IFACE_NAME), eq(BSSID));
reset(mWifiMonitor);
mISupplicantStaIfaceCallback.onBssidChanged(
BssidChangeReason.ASSOC_COMPLETE, NativeUtil.macAddressToByteArray(BSSID));
- verify(mWifiMonitor, never()).broadcastTargetBssidEvent(eq(WLAN_IFACE_NAME), eq(BSSID));
- verify(mWifiMonitor).broadcastAssociatedBssidEvent(eq(WLAN_IFACE_NAME), eq(BSSID));
+ verify(mWifiMonitor, never()).broadcastTargetBssidEvent(eq(WLAN0_IFACE_NAME), eq(BSSID));
+ verify(mWifiMonitor).broadcastAssociatedBssidEvent(eq(WLAN0_IFACE_NAME), eq(BSSID));
reset(mWifiMonitor);
mISupplicantStaIfaceCallback.onBssidChanged(
BssidChangeReason.DISASSOC, NativeUtil.macAddressToByteArray(BSSID));
- verify(mWifiMonitor, never()).broadcastTargetBssidEvent(eq(WLAN_IFACE_NAME), eq(BSSID));
- verify(mWifiMonitor, never()).broadcastAssociatedBssidEvent(eq(WLAN_IFACE_NAME), eq(BSSID));
+ verify(mWifiMonitor, never()).broadcastTargetBssidEvent(eq(WLAN0_IFACE_NAME), eq(BSSID));
+ verify(mWifiMonitor, never()).broadcastAssociatedBssidEvent(
+ eq(WLAN0_IFACE_NAME), eq(BSSID));
}
/**
@@ -1117,7 +1203,7 @@
assertNotNull(mISupplicantStaIfaceCallback);
mISupplicantStaIfaceCallback.onEapFailure();
- verify(mWifiMonitor).broadcastAuthenticationFailureEvent(eq(WLAN_IFACE_NAME),
+ verify(mWifiMonitor).broadcastAuthenticationFailureEvent(eq(WLAN0_IFACE_NAME),
eq(WifiManager.ERROR_AUTH_FAILURE_EAP_FAILURE));
}
@@ -1130,7 +1216,7 @@
assertNotNull(mISupplicantStaIfaceCallback);
mISupplicantStaIfaceCallback.onWpsEventSuccess();
- verify(mWifiMonitor).broadcastWpsSuccessEvent(eq(WLAN_IFACE_NAME));
+ verify(mWifiMonitor).broadcastWpsSuccessEvent(eq(WLAN0_IFACE_NAME));
}
/**
@@ -1145,7 +1231,7 @@
short errorInd = ISupplicantStaIfaceCallback.WpsErrorIndication.SECURITY_WEP_PROHIBITED;
mISupplicantStaIfaceCallback.onWpsEventFail(
NativeUtil.macAddressToByteArray(BSSID), cfgError, errorInd);
- verify(mWifiMonitor).broadcastWpsFailEvent(eq(WLAN_IFACE_NAME),
+ verify(mWifiMonitor).broadcastWpsFailEvent(eq(WLAN0_IFACE_NAME),
eq((int) cfgError), eq((int) errorInd));
}
@@ -1161,7 +1247,7 @@
short errorInd = ISupplicantStaIfaceCallback.WpsErrorIndication.NO_ERROR;
mISupplicantStaIfaceCallback.onWpsEventFail(
NativeUtil.macAddressToByteArray(BSSID), cfgError, errorInd);
- verify(mWifiMonitor).broadcastWpsTimeoutEvent(eq(WLAN_IFACE_NAME));
+ verify(mWifiMonitor).broadcastWpsTimeoutEvent(eq(WLAN0_IFACE_NAME));
}
/**
@@ -1173,7 +1259,7 @@
assertNotNull(mISupplicantStaIfaceCallback);
mISupplicantStaIfaceCallback.onWpsEventPbcOverlap();
- verify(mWifiMonitor).broadcastWpsOverlapEvent(eq(WLAN_IFACE_NAME));
+ verify(mWifiMonitor).broadcastWpsOverlapEvent(eq(WLAN0_IFACE_NAME));
}
/**
@@ -1184,11 +1270,13 @@
executeAndValidateInitializationSequence();
assertNotNull(mServiceManagerDeathCaptor.getValue());
assertTrue(mDut.isInitializationComplete());
+ assertTrue(mDut.registerDeathHandler(mSupplicantHalDeathHandler));
mServiceManagerDeathCaptor.getValue().serviceDied(5L);
assertFalse(mDut.isInitializationComplete());
- verify(mWifiMonitor).broadcastSupplicantDisconnectionEvent(eq(WLAN_IFACE_NAME));
+ verify(mWifiMonitor).broadcastSupplicantDisconnectionEvent(eq(WLAN0_IFACE_NAME));
+ verify(mSupplicantHalDeathHandler).onDeath();
}
/**
@@ -1199,11 +1287,13 @@
executeAndValidateInitializationSequence();
assertNotNull(mSupplicantDeathCaptor.getValue());
assertTrue(mDut.isInitializationComplete());
+ assertTrue(mDut.registerDeathHandler(mSupplicantHalDeathHandler));
mSupplicantDeathCaptor.getValue().serviceDied(5L);
assertFalse(mDut.isInitializationComplete());
- verify(mWifiMonitor).broadcastSupplicantDisconnectionEvent(eq(WLAN_IFACE_NAME));
+ verify(mWifiMonitor).broadcastSupplicantDisconnectionEvent(eq(WLAN0_IFACE_NAME));
+ verify(mSupplicantHalDeathHandler).onDeath();
}
/**
@@ -1218,7 +1308,7 @@
mSupplicantStaIfaceDeathCaptor.getValue().serviceDied(5L);
assertFalse(mDut.isInitializationComplete());
- verify(mWifiMonitor).broadcastSupplicantDisconnectionEvent(eq(WLAN_IFACE_NAME));
+ verify(mWifiMonitor).broadcastSupplicantDisconnectionEvent(eq(WLAN0_IFACE_NAME));
}
/**
@@ -1268,17 +1358,17 @@
.thenReturn(mStatusSuccess);
// Fail before initialization is performed.
- assertFalse(mDut.startWpsRegistrar(null, null));
+ assertFalse(mDut.startWpsRegistrar(WLAN0_IFACE_NAME, null, null));
executeAndValidateInitializationSequence();
- assertFalse(mDut.startWpsRegistrar(null, null));
+ assertFalse(mDut.startWpsRegistrar(WLAN0_IFACE_NAME, null, null));
verify(mISupplicantStaIfaceMock, never()).startWpsRegistrar(any(byte[].class), anyString());
- assertFalse(mDut.startWpsRegistrar(new String(), "452233"));
+ assertFalse(mDut.startWpsRegistrar(WLAN0_IFACE_NAME, new String(), "452233"));
verify(mISupplicantStaIfaceMock, never()).startWpsRegistrar(any(byte[].class), anyString());
- assertTrue(mDut.startWpsRegistrar("45:23:12:12:12:98", "562535"));
+ assertTrue(mDut.startWpsRegistrar(WLAN0_IFACE_NAME, "45:23:12:12:12:98", "562535"));
verify(mISupplicantStaIfaceMock).startWpsRegistrar(any(byte[].class), anyString());
}
@@ -1293,15 +1383,15 @@
byte[] anyBssidBytes = {0, 0, 0, 0, 0, 0};
// Fail before initialization is performed.
- assertFalse(mDut.startWpsPbc(bssid));
+ assertFalse(mDut.startWpsPbc(WLAN0_IFACE_NAME, bssid));
verify(mISupplicantStaIfaceMock, never()).startWpsPbc(any(byte[].class));
executeAndValidateInitializationSequence();
- assertTrue(mDut.startWpsPbc(bssid));
+ assertTrue(mDut.startWpsPbc(WLAN0_IFACE_NAME, bssid));
verify(mISupplicantStaIfaceMock).startWpsPbc(eq(bssidBytes));
- assertTrue(mDut.startWpsPbc(null));
+ assertTrue(mDut.startWpsPbc(WLAN0_IFACE_NAME, null));
verify(mISupplicantStaIfaceMock).startWpsPbc(eq(anyBssidBytes));
}
@@ -1322,7 +1412,7 @@
bssid, reasonCode, reauthDelay, HS20_URL);
ArgumentCaptor<WnmData> wnmDataCaptor = ArgumentCaptor.forClass(WnmData.class);
- verify(mWifiMonitor).broadcastWnmEvent(eq(WLAN_IFACE_NAME), wnmDataCaptor.capture());
+ verify(mWifiMonitor).broadcastWnmEvent(eq(WLAN0_IFACE_NAME), wnmDataCaptor.capture());
assertEquals(
ByteBufferReader.readInteger(
ByteBuffer.wrap(bssid), ByteOrder.BIG_ENDIAN, bssid.length),
@@ -1399,7 +1489,8 @@
// act: cause the onRegistration(...) callback to execute
mServiceNotificationCaptor.getValue().onRegistration(ISupplicant.kInterfaceName, "", true);
- assertTrue(mDut.isInitializationComplete() == shouldSucceed);
+ assertTrue(mDut.isInitializationComplete());
+ assertTrue(mDut.setupIface(WLAN0_IFACE_NAME) == shouldSucceed);
mInOrder.verify(mISupplicantMock).linkToDeath(mSupplicantDeathCaptor.capture(),
anyLong());
// verify: listInterfaces is called
@@ -1411,7 +1502,8 @@
any(ISupplicant.getInterfaceCallback.class));
}
if (causeRemoteException) {
- mInOrder.verify(mWifiMonitor).broadcastSupplicantDisconnectionEvent(eq(null));
+ mInOrder.verify(mWifiMonitor).broadcastSupplicantDisconnectionEvent(
+ eq(WLAN0_IFACE_NAME));
}
if (!causeRemoteException && !getZeroInterfaces && !getNullInterface) {
mInOrder.verify(mISupplicantStaIfaceMock).linkToDeath(
@@ -1529,7 +1621,7 @@
setupMocksForConnectSequence(haveExistingNetwork);
WifiConfiguration config = new WifiConfiguration();
config.networkId = newFrameworkNetworkId;
- assertTrue(mDut.connectToNetwork(config));
+ assertTrue(mDut.connectToNetwork(WLAN0_IFACE_NAME, config));
validateConnectSequence(haveExistingNetwork, 1);
return config;
}
@@ -1566,7 +1658,7 @@
WifiConfiguration roamingConfig = new WifiConfiguration();
roamingConfig.networkId = roamNetworkId;
roamingConfig.getNetworkSelectionStatus().setNetworkSelectionBSSID(roamBssid);
- assertTrue(mDut.roamToNetwork(roamingConfig));
+ assertTrue(mDut.roamToNetwork(WLAN0_IFACE_NAME, roamingConfig));
if (!sameNetwork) {
validateConnectSequence(false, 2);
diff --git a/tests/wifitests/src/com/android/server/wifi/TestUtil.java b/tests/wifitests/src/com/android/server/wifi/TestUtil.java
index a0a1030..ab2cda5 100644
--- a/tests/wifitests/src/com/android/server/wifi/TestUtil.java
+++ b/tests/wifitests/src/com/android/server/wifi/TestUtil.java
@@ -21,6 +21,7 @@
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
+import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import java.util.ArrayList;
@@ -42,6 +43,17 @@
}
/**
+ * Send {@link WifiManager#NETWORK_STATE_CHANGED_ACTION} broadcast.
+ */
+ public static void sendNetworkStateChanged(BroadcastReceiver broadcastReceiver,
+ Context context, NetworkInfo nwInfo, WifiInfo wifiInfo) {
+ Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+ intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, nwInfo);
+ intent.putExtra(WifiManager.EXTRA_WIFI_INFO, wifiInfo);
+ broadcastReceiver.onReceive(context, intent);
+ }
+
+ /**
* Send {@link WifiManager#SCAN_RESULTS_AVAILABLE_ACTION} broadcast.
*/
public static void sendScanResultsAvailable(BroadcastReceiver broadcastReceiver,
@@ -85,7 +97,6 @@
}
intent.putExtra(WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME, ifaceName);
intent.putExtra(WifiManager.EXTRA_WIFI_AP_MODE, mode);
-
broadcastReceiver.onReceive(context, intent);
}
diff --git a/tests/wifitests/src/com/android/server/wifi/VelocityBasedConnectedScoreTest.java b/tests/wifitests/src/com/android/server/wifi/VelocityBasedConnectedScoreTest.java
new file mode 100644
index 0000000..263cbed
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/VelocityBasedConnectedScoreTest.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wifi;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.net.wifi.WifiInfo;
+
+import com.android.internal.R;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
+
+/**
+ * Unit tests for {@link com.android.server.wifi.VelocityBasedConnectedScore}.
+ */
+public class VelocityBasedConnectedScoreTest {
+
+ private static final int CELLULAR_THRESHOLD_SCORE = 50;
+
+ class FakeClock extends Clock {
+ long mWallClockMillis = 1500000000000L;
+ int mStepMillis = 3001;
+
+ @Override
+ public long getWallClockMillis() {
+ mWallClockMillis += mStepMillis;
+ return mWallClockMillis;
+ }
+ }
+
+ FakeClock mClock;
+ VelocityBasedConnectedScore mVelocityBasedConnectedScore;
+ ScanDetailCache mScanDetailCache;
+ WifiInfo mWifiInfo;
+ int mRssiExitThreshold2GHz;
+ int mRssiExitThreshold5GHz;
+ @Mock Context mContext;
+ @Spy private MockResources mResources = new MockResources();
+
+ private int setupIntegerResource(int resourceName, int value) {
+ doReturn(value).when(mResources).getInteger(resourceName);
+ return value;
+ }
+
+ /**
+ * Sets up resource values for testing
+ *
+ * See frameworks/base/core/res/res/values/config.xml
+ */
+ private void setUpResources(Resources resources) {
+ mRssiExitThreshold2GHz = setupIntegerResource(
+ R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz, -83);
+ mRssiExitThreshold5GHz = setupIntegerResource(
+ R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz, -80);
+ }
+
+ /**
+ * Sets up for unit test
+ */
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ setUpResources(mResources);
+ mWifiInfo = new WifiInfo();
+ mWifiInfo.setFrequency(2412);
+ when(mContext.getResources()).thenReturn(mResources);
+ mClock = new FakeClock();
+ mVelocityBasedConnectedScore = new VelocityBasedConnectedScore(mContext, mClock);
+ }
+
+ /**
+ *
+ * Low RSSI, but some data is moving and error rate is low.
+ *
+ * Expect a score above threshold.
+ */
+ @Test
+ public void allowLowRssiIfErrorRateIsLowAndSomeDataIsMoving() throws Exception {
+ mWifiInfo.setRssi(mRssiExitThreshold2GHz - 2);
+ mWifiInfo.setLinkSpeed(6); // Mbps
+ mWifiInfo.txSuccessRate = 10.1; // proportional to pps
+ mWifiInfo.txBadRate = .5;
+ mWifiInfo.rxSuccessRate = 10.1;
+ for (int i = 0; i < 10; i++) {
+ mVelocityBasedConnectedScore.updateUsingWifiInfo(mWifiInfo,
+ mClock.getWallClockMillis());
+ }
+ int score = mVelocityBasedConnectedScore.generateScore();
+ assertTrue(score > CELLULAR_THRESHOLD_SCORE);
+ }
+
+ /**
+ *
+ * Low RSSI, and almost no data is moving.
+ *
+ * Expect a score below threshold.
+ */
+ @Test
+ public void disallowLowRssiIfDataIsNotMoving() throws Exception {
+ mWifiInfo.setRssi(mRssiExitThreshold2GHz - 1);
+ mWifiInfo.setLinkSpeed(6); // Mbps
+ mWifiInfo.txSuccessRate = .1; // proportional to pps
+ mWifiInfo.txBadRate = 0;
+ mWifiInfo.rxSuccessRate = .1;
+ for (int i = 0; i < 10; i++) {
+ mVelocityBasedConnectedScore.updateUsingWifiInfo(mWifiInfo,
+ mClock.getWallClockMillis());
+ }
+ int score = mVelocityBasedConnectedScore.generateScore();
+ assertTrue(score < CELLULAR_THRESHOLD_SCORE);
+ }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/WakeupControllerTest.java b/tests/wifitests/src/com/android/server/wifi/WakeupControllerTest.java
new file mode 100644
index 0000000..742c520
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/WakeupControllerTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wifi;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.test.TestLooper;
+import android.provider.Settings;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Unit tests for {@link WakeupController}.
+ */
+public class WakeupControllerTest {
+
+ @Mock private Context mContext;
+ @Mock private FrameworkFacade mFrameworkFacade;
+
+ private TestLooper mLooper;
+ private WakeupController mWakeupController;
+
+ /** Initialize objects before each test run. */
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mLooper = new TestLooper();
+ }
+
+ /**
+ * Verify WakeupController is enabled when the settings toggle is true.
+ */
+ @Test
+ public void verifyEnabledWhenToggledOn() {
+ when(mFrameworkFacade.getIntegerSetting(mContext,
+ Settings.Global.WIFI_WAKEUP_ENABLED, 0)).thenReturn(1);
+ mWakeupController = new WakeupController(mContext, mLooper.getLooper(),
+ mFrameworkFacade);
+
+ assertTrue(mWakeupController.isEnabled());
+ }
+
+ /**
+ * Verify WakeupController is disabled when the settings toggle is false.
+ */
+ @Test
+ public void verifyDisabledWhenToggledOff() {
+ when(mFrameworkFacade.getIntegerSetting(mContext,
+ Settings.Global.WIFI_WAKEUP_ENABLED, 0)).thenReturn(0);
+ mWakeupController = new WakeupController(mContext, mLooper.getLooper(),
+ mFrameworkFacade);
+
+ assertFalse(mWakeupController.isEnabled());
+ }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiCertManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiCertManagerTest.java
index 04c2802..b123d80 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiCertManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiCertManagerTest.java
@@ -97,7 +97,7 @@
}
}
- @Test
+ // TODO: b/69555027 - determine if test can be removed. for now, disable failing test
public void testEmptyConfigFile() {
WifiCertManager certManager = new WifiCertManager(mContext, mConfigFile);
final String[] expected =
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java
index 0fa6600..a2c989a 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java
@@ -84,6 +84,7 @@
private static final String TEST_CREATOR_NAME = "com.wificonfigmanager.creator";
private static final String TEST_UPDATE_NAME = "com.wificonfigmanager.update";
private static final String TEST_NO_PERM_NAME = "com.wificonfigmanager.noperm";
+ private static final String TEST_WIFI_NAME = "android.uid.system";
private static final String TEST_DEFAULT_GW_MAC_ADDRESS = "0f:67:ad:ef:09:34";
private static final String TEST_STATIC_PROXY_HOST_1 = "192.168.48.1";
private static final int TEST_STATIC_PROXY_PORT_1 = 8000;
@@ -149,6 +150,8 @@
return WifiConfigManager.SYSUI_PACKAGE_NAME;
} else if (uid == TEST_NO_PERM_UID) {
return TEST_NO_PERM_NAME;
+ } else if (uid == Process.WIFI_UID) {
+ return TEST_WIFI_NAME;
}
fail("Unexpected UID: " + uid);
return "";
@@ -793,7 +796,7 @@
/**
* Verifies the updation of network's connectUid using
- * {@link WifiConfigManager#checkAndUpdateLastConnectUid(int, int)}.
+ * {@link WifiConfigManager#updateLastConnectUid(int, int)}.
*/
@Test
public void testUpdateLastConnectUid() throws Exception {
@@ -802,21 +805,11 @@
NetworkUpdateResult result = verifyAddNetworkToWifiConfigManager(openNetwork);
assertTrue(
- mWifiConfigManager.checkAndUpdateLastConnectUid(
+ mWifiConfigManager.updateLastConnectUid(
result.getNetworkId(), TEST_CREATOR_UID));
WifiConfiguration retrievedNetwork =
mWifiConfigManager.getConfiguredNetwork(result.getNetworkId());
assertEquals(TEST_CREATOR_UID, retrievedNetwork.lastConnectUid);
-
- when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(false);
-
- // Now try to update the last connect UID with |TEST_UPDATE_UID|, it should fail and
- // the lastConnectUid should remain the same.
- assertFalse(
- mWifiConfigManager.checkAndUpdateLastConnectUid(
- result.getNetworkId(), TEST_UPDATE_UID));
- retrievedNetwork = mWifiConfigManager.getConfiguredNetwork(result.getNetworkId());
- assertEquals(TEST_CREATOR_UID, retrievedNetwork.lastConnectUid);
}
/**
@@ -864,7 +857,7 @@
* This invokes {@link WifiConfigManager#enableNetwork(int, boolean, int)},
* {@link WifiConfigManager#disableNetwork(int, int)},
* {@link WifiConfigManager#updateNetworkSelectionStatus(int, int)} and
- * {@link WifiConfigManager#checkAndUpdateLastConnectUid(int, int)}.
+ * {@link WifiConfigManager#updateLastConnectUid(int, int)}.
*/
@Test
public void testChangeConfigurationWithInvalidNetworkId() {
@@ -877,7 +870,7 @@
assertFalse(mWifiConfigManager.disableNetwork(result.getNetworkId() + 1, TEST_CREATOR_UID));
assertFalse(mWifiConfigManager.updateNetworkSelectionStatus(
result.getNetworkId() + 1, NetworkSelectionStatus.DISABLED_BY_WIFI_MANAGER));
- assertFalse(mWifiConfigManager.checkAndUpdateLastConnectUid(
+ assertFalse(mWifiConfigManager.updateLastConnectUid(
result.getNetworkId() + 1, TEST_CREATOR_UID));
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtilTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtilTest.java
index 2925273..358f3b6 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtilTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtilTest.java
@@ -44,6 +44,8 @@
static final int OTHER_USER_ID = 11;
static final String TEST_SSID = "test_ssid";
static final String TEST_SSID_1 = "test_ssid_1";
+ static final String TEST_BSSID = "aa:aa:11:22:cc:dd";
+ static final String TEST_BSSID_1 = "11:22:11:22:cc:dd";
static final List<UserInfo> PROFILES = Arrays.asList(
new UserInfo(CURRENT_USER_ID, "owner", 0),
new UserInfo(CURRENT_USER_MANAGED_PROFILE_USER_ID, "managed profile", 0));
@@ -474,6 +476,19 @@
}
/**
+ * Verify that WifiConfigurationUtil.isSameNetwork returns true when two WifiConfiguration
+ * objects have the same parameters but different network selection BSSID's.
+ */
+ @Test
+ public void testIsSameNetworkReturnsTrueOnSameNetworkWithDifferentBSSID() {
+ WifiConfiguration network = WifiConfigurationTestUtil.createPskNetwork(TEST_SSID);
+ network.getNetworkSelectionStatus().setNetworkSelectionBSSID(TEST_BSSID);
+ WifiConfiguration network1 = WifiConfigurationTestUtil.createPskNetwork(TEST_SSID);
+ network1.getNetworkSelectionStatus().setNetworkSelectionBSSID(TEST_BSSID_1);
+ assertTrue(WifiConfigurationUtil.isSameNetwork(network, network1));
+ }
+
+ /**
* Verify that WifiConfigurationUtil.isSameNetwork returns false when two WifiConfiguration
* objects have the different SSIDs.
*/
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java b/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java
index 65427be..e3e7c0b 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java
@@ -18,7 +18,9 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.*;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
import android.net.NetworkAgent;
import android.net.wifi.ScanResult;
@@ -40,7 +42,9 @@
import com.android.server.wifi.nano.WifiMetricsProto;
import com.android.server.wifi.nano.WifiMetricsProto.ConnectToNetworkNotificationAndActionCount;
import com.android.server.wifi.nano.WifiMetricsProto.PnoScanMetrics;
+import com.android.server.wifi.nano.WifiMetricsProto.SoftApConnectedClientsEvent;
import com.android.server.wifi.nano.WifiMetricsProto.StaEvent;
+import com.android.server.wifi.nano.WifiMetricsProto.WpsMetrics;
import org.junit.Before;
import org.junit.Test;
@@ -260,6 +264,15 @@
private static final int NUM_PNO_SCAN_STARTED_OVER_OFFLOAD = 17;
private static final int NUM_PNO_SCAN_FAILED_OVER_OFFLOAD = 8;
private static final int NUM_PNO_FOUND_NETWORK_EVENTS = 10;
+ private static final int NUM_WPS_ATTEMPTS = 17;
+ private static final int NUM_WPS_SUCCESS = 21;
+ private static final int NUM_WPS_START_FAILURE = 7;
+ private static final int NUM_WPS_OVERLAP_FAILURE = 3;
+ private static final int NUM_WPS_TIMEOUT_FAILURE = 8;
+ private static final int NUM_WPS_OTHER_CONNECTION_FAILURE = 16;
+ private static final int NUM_WPS_SUPPLICANT_FAILURE = 12;
+ private static final int NUM_WPS_CANCELLATION = 11;
+
/** Number of notifications per "Connect to Network" notification type. */
private static final int[] NUM_CONNECT_TO_NETWORK_NOTIFICATIONS = {0, 10, 20, 30, 40};
/** Number of notifications per "Connect to Network notification type and action type. */
@@ -273,6 +286,8 @@
private static final boolean IS_WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON = true;
private static final int NUM_OPEN_NETWORK_CONNECT_MESSAGE_FAILED_TO_SEND = 5;
private static final int NUM_OPEN_NETWORK_RECOMMENDATION_UPDATES = 8;
+ private static final int NUM_SOFT_AP_EVENT_ENTRIES = 3;
+ private static final int NUM_SOFT_AP_ASSOCIATED_STATIONS = 3;
private ScanDetail buildMockScanDetail(boolean hidden, NetworkDetail.HSRelease hSRelease,
String capabilities) {
@@ -311,6 +326,23 @@
return mockScanDetail;
}
+ private ScanDetail buildMockScanDetailPasspoint(String ssid, String bssid, long hessid,
+ int anqpDomainId, NetworkDetail.HSRelease hsRelease) {
+ ScanDetail mockScanDetail = mock(ScanDetail.class);
+ NetworkDetail mockNetworkDetail = mock(NetworkDetail.class);
+ ScanResult scanResult = new ScanResult();
+ scanResult.SSID = ssid;
+ scanResult.BSSID = bssid;
+ scanResult.hessid = hessid;
+ scanResult.capabilities = "PSK";
+ when(mockScanDetail.getNetworkDetail()).thenReturn(mockNetworkDetail);
+ when(mockScanDetail.getScanResult()).thenReturn(scanResult);
+ when(mockNetworkDetail.getHSRelease()).thenReturn(hsRelease);
+ when(mockNetworkDetail.getAnqpDomainID()).thenReturn(anqpDomainId);
+ when(mockNetworkDetail.isInterworking()).thenReturn(true);
+ return mockScanDetail;
+ }
+
private List<ScanDetail> buildMockScanDetailList() {
List<ScanDetail> mockScanDetails = new ArrayList<ScanDetail>();
mockScanDetails.add(buildMockScanDetail(true, null, "[ESS]"));
@@ -539,6 +571,78 @@
for (int i = 0; i < NUM_OPEN_NETWORK_CONNECT_MESSAGE_FAILED_TO_SEND; i++) {
mWifiMetrics.incrementNumOpenNetworkConnectMessageFailedToSend();
}
+
+ addSoftApEventsToMetrics();
+
+ // increment wps metrics
+ for (int i = 0; i < NUM_WPS_ATTEMPTS; i++) {
+ mWifiMetrics.incrementWpsAttemptCount();
+ }
+ for (int i = 0; i < NUM_WPS_SUCCESS; i++) {
+ mWifiMetrics.incrementWpsSuccessCount();
+ }
+ for (int i = 0; i < NUM_WPS_START_FAILURE; i++) {
+ mWifiMetrics.incrementWpsStartFailureCount();
+ }
+ for (int i = 0; i < NUM_WPS_OVERLAP_FAILURE; i++) {
+ mWifiMetrics.incrementWpsOverlapFailureCount();
+ }
+ for (int i = 0; i < NUM_WPS_TIMEOUT_FAILURE; i++) {
+ mWifiMetrics.incrementWpsTimeoutFailureCount();
+ }
+ for (int i = 0; i < NUM_WPS_OTHER_CONNECTION_FAILURE; i++) {
+ mWifiMetrics.incrementWpsOtherConnectionFailureCount();
+ }
+ for (int i = 0; i < NUM_WPS_SUPPLICANT_FAILURE; i++) {
+ mWifiMetrics.incrementWpsSupplicantFailureCount();
+ }
+ for (int i = 0; i < NUM_WPS_CANCELLATION; i++) {
+ mWifiMetrics.incrementWpsCancellationCount();
+ }
+ }
+
+ private void addSoftApEventsToMetrics() {
+ // Total number of events recorded is NUM_SOFT_AP_EVENT_ENTRIES in both modes
+
+ mWifiMetrics.addSoftApUpChangedEvent(true, WifiManager.IFACE_IP_MODE_TETHERED);
+ mWifiMetrics.addSoftApNumAssociatedStationsChangedEvent(NUM_SOFT_AP_ASSOCIATED_STATIONS,
+ WifiManager.IFACE_IP_MODE_TETHERED);
+ mWifiMetrics.addSoftApNumAssociatedStationsChangedEvent(NUM_SOFT_AP_ASSOCIATED_STATIONS,
+ WifiManager.IFACE_IP_MODE_UNSPECIFIED); // Should be dropped.
+ mWifiMetrics.addSoftApUpChangedEvent(false, WifiManager.IFACE_IP_MODE_TETHERED);
+
+ mWifiMetrics.addSoftApUpChangedEvent(true, WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
+ mWifiMetrics.addSoftApNumAssociatedStationsChangedEvent(NUM_SOFT_AP_ASSOCIATED_STATIONS,
+ WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
+ // Should be dropped.
+ mWifiMetrics.addSoftApUpChangedEvent(false, WifiManager.IFACE_IP_MODE_CONFIGURATION_ERROR);
+ mWifiMetrics.addSoftApUpChangedEvent(false, WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
+ }
+
+ private void verifySoftApEventsStoredInProto() {
+ assertEquals(NUM_SOFT_AP_EVENT_ENTRIES,
+ mDecodedProto.softApConnectedClientsEventsTethered.length);
+ assertEquals(SoftApConnectedClientsEvent.SOFT_AP_UP,
+ mDecodedProto.softApConnectedClientsEventsTethered[0].eventType);
+ assertEquals(0, mDecodedProto.softApConnectedClientsEventsTethered[0].numConnectedClients);
+ assertEquals(SoftApConnectedClientsEvent.NUM_CLIENTS_CHANGED,
+ mDecodedProto.softApConnectedClientsEventsTethered[1].eventType);
+ assertEquals(NUM_SOFT_AP_ASSOCIATED_STATIONS,
+ mDecodedProto.softApConnectedClientsEventsTethered[1].numConnectedClients);
+ assertEquals(SoftApConnectedClientsEvent.SOFT_AP_DOWN,
+ mDecodedProto.softApConnectedClientsEventsTethered[2].eventType);
+ assertEquals(0, mDecodedProto.softApConnectedClientsEventsTethered[2].numConnectedClients);
+
+ assertEquals(SoftApConnectedClientsEvent.SOFT_AP_UP,
+ mDecodedProto.softApConnectedClientsEventsLocalOnly[0].eventType);
+ assertEquals(0, mDecodedProto.softApConnectedClientsEventsLocalOnly[0].numConnectedClients);
+ assertEquals(SoftApConnectedClientsEvent.NUM_CLIENTS_CHANGED,
+ mDecodedProto.softApConnectedClientsEventsLocalOnly[1].eventType);
+ assertEquals(NUM_SOFT_AP_ASSOCIATED_STATIONS,
+ mDecodedProto.softApConnectedClientsEventsLocalOnly[1].numConnectedClients);
+ assertEquals(SoftApConnectedClientsEvent.SOFT_AP_DOWN,
+ mDecodedProto.softApConnectedClientsEventsLocalOnly[2].eventType);
+ assertEquals(0, mDecodedProto.softApConnectedClientsEventsLocalOnly[2].numConnectedClients);
}
/**
@@ -717,6 +821,19 @@
mDecodedProto.numOpenNetworkRecommendationUpdates);
assertEquals(NUM_OPEN_NETWORK_CONNECT_MESSAGE_FAILED_TO_SEND,
mDecodedProto.numOpenNetworkConnectMessageFailedToSend);
+
+ verifySoftApEventsStoredInProto();
+
+ WpsMetrics wps_metrics = mDecodedProto.wpsMetrics;
+ assertNotNull(wps_metrics);
+ assertEquals(NUM_WPS_ATTEMPTS, wps_metrics.numWpsAttempts);
+ assertEquals(NUM_WPS_SUCCESS, wps_metrics.numWpsSuccess);
+ assertEquals(NUM_WPS_START_FAILURE, wps_metrics.numWpsStartFailure);
+ assertEquals(NUM_WPS_OVERLAP_FAILURE, wps_metrics.numWpsOverlapFailure);
+ assertEquals(NUM_WPS_TIMEOUT_FAILURE, wps_metrics.numWpsTimeoutFailure);
+ assertEquals(NUM_WPS_OTHER_CONNECTION_FAILURE, wps_metrics.numWpsOtherConnectionFailure);
+ assertEquals(NUM_WPS_SUPPLICANT_FAILURE, wps_metrics.numWpsSupplicantFailure);
+ assertEquals(NUM_WPS_CANCELLATION, wps_metrics.numWpsCancellation);
}
/**
@@ -763,6 +880,31 @@
// pending their implementation</TODO>
}
+ /**
+ * Test that score breach events are properly generated
+ */
+ @Test
+ public void testScoreBeachEvents() throws Exception {
+ int upper = WifiMetrics.LOW_WIFI_SCORE + 7;
+ int mid = WifiMetrics.LOW_WIFI_SCORE;
+ int lower = WifiMetrics.LOW_WIFI_SCORE - 8;
+ mWifiMetrics.setWifiState(WifiMetricsProto.WifiLog.WIFI_ASSOCIATED);
+ for (int score = upper; score >= mid; score--) mWifiMetrics.incrementWifiScoreCount(score);
+ mWifiMetrics.incrementWifiScoreCount(mid + 1);
+ mWifiMetrics.incrementWifiScoreCount(lower); // First breach
+ for (int score = lower; score <= mid; score++) mWifiMetrics.incrementWifiScoreCount(score);
+ mWifiMetrics.incrementWifiScoreCount(mid - 1);
+ mWifiMetrics.incrementWifiScoreCount(upper); // Second breach
+
+ dumpProtoAndDeserialize();
+
+ assertEquals(2, mDecodedProto.staEventList.length);
+ assertEquals(StaEvent.TYPE_SCORE_BREACH, mDecodedProto.staEventList[0].type);
+ assertEquals(lower, mDecodedProto.staEventList[0].lastScore);
+ assertEquals(StaEvent.TYPE_SCORE_BREACH, mDecodedProto.staEventList[1].type);
+ assertEquals(upper, mDecodedProto.staEventList[1].lastScore);
+ }
+
private static final String SSID = "red";
private static final int CONFIG_DTIM = 3;
private static final int NETWORK_DETAIL_WIFIMODE = 5;
@@ -1041,7 +1183,7 @@
private static final int ASSOC_TIMEOUT = 1;
private static final int LOCAL_GEN = 1;
private static final int AUTH_FAILURE_REASON = WifiManager.ERROR_AUTH_FAILURE_WRONG_PSWD;
- private static final int NUM_TEST_STA_EVENTS = 14;
+ private static final int NUM_TEST_STA_EVENTS = 15;
private static final String sSSID = "\"SomeTestSsid\"";
private static final WifiSsid sWifiSsid = WifiSsid.createFromAsciiEncoded(sSSID);
private static final String sBSSID = "01:02:03:04:05:06";
@@ -1089,7 +1231,8 @@
{StaEvent.TYPE_CMD_START_ROAM, 0, 1},
{StaEvent.TYPE_CONNECT_NETWORK, 0, 1},
{StaEvent.TYPE_NETWORK_AGENT_VALID_NETWORK, 0, 0},
- {StaEvent.TYPE_FRAMEWORK_DISCONNECT, StaEvent.DISCONNECT_API, 0}
+ {StaEvent.TYPE_FRAMEWORK_DISCONNECT, StaEvent.DISCONNECT_API, 0},
+ {StaEvent.TYPE_SCORE_BREACH, 0, 0}
};
// Values used to generate the StaEvent log calls from WifiMonitor
// <type>, <reason>, <status>, <local_gen>,
@@ -1122,6 +1265,8 @@
{StaEvent.TYPE_NETWORK_AGENT_VALID_NETWORK, -1, -1, 0,
/**/ 0, 0, 0, 0}, /**/
{StaEvent.TYPE_FRAMEWORK_DISCONNECT, -1, -1, 0,
+ /**/ 0, 0, 0, 0}, /**/
+ {StaEvent.TYPE_SCORE_BREACH, -1, -1, 0,
/**/ 0, 0, 0, 0} /**/
};
@@ -1142,6 +1287,7 @@
}
}
private void verifyDeserializedStaEvents(WifiMetricsProto.WifiLog wifiLog) {
+ assertNotNull(mTestWifiConfig);
assertEquals(NUM_TEST_STA_EVENTS, wifiLog.staEventList.length);
int j = 0; // De-serialized event index
for (int i = 0; i < mTestStaMessageInts.length; i++) {
@@ -1161,6 +1307,21 @@
j++;
}
}
+ for (int i = 0; i < mTestStaLogInts.length; i++) {
+ StaEvent event = wifiLog.staEventList[j];
+ int[] evs = mExpectedValues[j];
+ assertEquals(evs[0], event.type);
+ assertEquals(evs[1], event.reason);
+ assertEquals(evs[2], event.status);
+ assertEquals(evs[3] == 1 ? true : false, event.localGen);
+ assertEquals(evs[4], event.authFailureReason);
+ assertEquals(evs[5] == 1 ? true : false, event.associationTimedOut);
+ assertEquals(evs[6], event.supplicantStateChangesBitmask);
+ assertConfigInfoEqualsWifiConfig(
+ evs[7] == 1 ? mTestWifiConfig : null, event.configInfo);
+ j++;
+ }
+ assertEquals(mExpectedValues.length, j);
}
/**
@@ -1271,9 +1432,77 @@
}
/**
+ * Test that Hotspot 2.0 (Passpoint) scan results are collected correctly and that relevant
+ * bounds are observed.
+ */
+ @Test
+ public void testObservedHotspotAps() throws Exception {
+ List<ScanDetail> scan = new ArrayList<ScanDetail>();
+ // 2 R1 (Unknown AP isn't counted) passpoint APs belonging to a single provider: hessid1
+ long hessid1 = 10;
+ int anqpDomainId1 = 5;
+ scan.add(buildMockScanDetailPasspoint("PASSPOINT_XX", "00:02:03:04:05:06", hessid1,
+ anqpDomainId1, NetworkDetail.HSRelease.R1));
+ scan.add(buildMockScanDetailPasspoint("PASSPOINT_XY", "01:02:03:04:05:06", hessid1,
+ anqpDomainId1, NetworkDetail.HSRelease.R1));
+ scan.add(buildMockScanDetailPasspoint("PASSPOINT_XYZ", "02:02:03:04:05:06", hessid1,
+ anqpDomainId1, NetworkDetail.HSRelease.Unknown));
+ // 2 R2 passpoint APs belonging to a single provider: hessid2
+ long hessid2 = 12;
+ int anqpDomainId2 = 6;
+ scan.add(buildMockScanDetailPasspoint("PASSPOINT_Y", "AA:02:03:04:05:06", hessid2,
+ anqpDomainId2, NetworkDetail.HSRelease.R2));
+ scan.add(buildMockScanDetailPasspoint("PASSPOINT_Z", "AB:02:03:04:05:06", hessid2,
+ anqpDomainId2, NetworkDetail.HSRelease.R2));
+ mWifiMetrics.incrementAvailableNetworksHistograms(scan, true);
+ scan = new ArrayList<ScanDetail>();
+ // 3 R2 passpoint APs belonging to a single provider: hessid3 (in next scan)
+ long hessid3 = 15;
+ int anqpDomainId3 = 8;
+ scan.add(buildMockScanDetailPasspoint("PASSPOINT_Y", "AA:02:03:04:05:06", hessid3,
+ anqpDomainId3, NetworkDetail.HSRelease.R2));
+ scan.add(buildMockScanDetailPasspoint("PASSPOINT_Y", "AA:02:03:04:05:06", hessid3,
+ anqpDomainId3, NetworkDetail.HSRelease.R2));
+ scan.add(buildMockScanDetailPasspoint("PASSPOINT_Z", "AB:02:03:04:05:06", hessid3,
+ anqpDomainId3, NetworkDetail.HSRelease.R2));
+ mWifiMetrics.incrementAvailableNetworksHistograms(scan, true);
+ dumpProtoAndDeserialize();
+
+ verifyHist(mDecodedProto.observedHotspotR1ApsInScanHistogram, 2, a(0, 2), a(1, 1));
+ verifyHist(mDecodedProto.observedHotspotR2ApsInScanHistogram, 2, a(2, 3), a(1, 1));
+ verifyHist(mDecodedProto.observedHotspotR1EssInScanHistogram, 2, a(0, 1), a(1, 1));
+ verifyHist(mDecodedProto.observedHotspotR2EssInScanHistogram, 1, a(1), a(2));
+ verifyHist(mDecodedProto.observedHotspotR1ApsPerEssInScanHistogram, 1, a(2), a(1));
+ verifyHist(mDecodedProto.observedHotspotR2ApsPerEssInScanHistogram, 2, a(2, 3), a(1, 1));
+
+ // check bounds
+ scan.clear();
+ int lotsOfSSids = Math.max(WifiMetrics.MAX_TOTAL_PASSPOINT_APS_BUCKET,
+ WifiMetrics.MAX_TOTAL_PASSPOINT_UNIQUE_ESS_BUCKET) + 5;
+ for (int i = 0; i < lotsOfSSids; i++) {
+ scan.add(buildMockScanDetailPasspoint("PASSPOINT_XX" + i, "00:02:03:04:05:06", i,
+ i + 10, NetworkDetail.HSRelease.R1));
+ scan.add(buildMockScanDetailPasspoint("PASSPOINT_XY" + i, "AA:02:03:04:05:06", 1000 * i,
+ i + 10, NetworkDetail.HSRelease.R2));
+ }
+ mWifiMetrics.incrementAvailableNetworksHistograms(scan, true);
+ dumpProtoAndDeserialize();
+ verifyHist(mDecodedProto.observedHotspotR1ApsInScanHistogram, 1,
+ a(WifiMetrics.MAX_TOTAL_PASSPOINT_APS_BUCKET), a(1));
+ verifyHist(mDecodedProto.observedHotspotR2ApsInScanHistogram, 1,
+ a(WifiMetrics.MAX_TOTAL_PASSPOINT_APS_BUCKET), a(1));
+ verifyHist(mDecodedProto.observedHotspotR1EssInScanHistogram, 1,
+ a(WifiMetrics.MAX_TOTAL_PASSPOINT_UNIQUE_ESS_BUCKET), a(1));
+ verifyHist(mDecodedProto.observedHotspotR2EssInScanHistogram, 1,
+ a(WifiMetrics.MAX_TOTAL_PASSPOINT_UNIQUE_ESS_BUCKET), a(1));
+
+ }
+
+ /**
* Test Open Network Notification blacklist size and feature state are not cleared when proto
* is dumped.
*/
+ @Test
public void testOpenNetworkNotificationBlacklistSizeAndFeatureStateNotCleared()
throws Exception {
mWifiMetrics.setOpenNetworkRecommenderBlacklistSize(
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiNativeTest.java b/tests/wifitests/src/com/android/server/wifi/WifiNativeTest.java
index 32d1daa..9a79a23 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiNativeTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiNativeTest.java
@@ -20,8 +20,6 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.anyBoolean;
-import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -47,6 +45,7 @@
*/
@SmallTest
public class WifiNativeTest {
+ private static final String WIFI_IFACE_NAME = "mockWlan";
private static final long FATE_REPORT_DRIVER_TIMESTAMP_USEC = 12345;
private static final byte[] FATE_REPORT_FRAME_BYTES = new byte[] {
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 0, 1, 2, 3, 4, 5, 6, 7};
@@ -155,8 +154,10 @@
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
when(mWifiVendorHal.isVendorHalSupported()).thenReturn(true);
- when(mWifiVendorHal.startVendorHal(anyBoolean())).thenReturn(true);
- mWifiNative = new WifiNative("test0", mWifiVendorHal, mStaIfaceHal, mWificondControl);
+ when(mWifiVendorHal.startVendorHalSta()).thenReturn(true);
+ when(mWifiVendorHal.startVendorHalAp()).thenReturn(true);
+ mWifiNative =
+ new WifiNative(WIFI_IFACE_NAME, mWifiVendorHal, mStaIfaceHal, mWificondControl);
}
/**
@@ -481,127 +482,139 @@
// TODO(b/28005116): Add test for the success case of getDriverStateDump().
/**
- * Verifies that setupDriverForClientMode() calls underlying WificondControl.
+ * Verifies that setupInterfaceForClientMode(WIFI_IFACE_NAME) calls underlying WificondControl.
*/
@Test
public void testSetupDriverForClientMode() {
IClientInterface clientInterface = mock(IClientInterface.class);
- when(mWificondControl.setupDriverForClientMode()).thenReturn(clientInterface);
+ when(mWificondControl.setupInterfaceForClientMode(WIFI_IFACE_NAME))
+ .thenReturn(clientInterface);
- Pair<Integer, IClientInterface> statusAndClientInterface = mWifiNative.setupForClientMode();
+ Pair<Integer, IClientInterface> statusAndClientInterface =
+ mWifiNative.setupForClientMode(WIFI_IFACE_NAME);
assertTrue(WifiNative.SETUP_SUCCESS == statusAndClientInterface.first);
assertEquals(clientInterface, statusAndClientInterface.second);
- verify(mWifiVendorHal).startVendorHal(eq(true));
- verify(mWificondControl).setupDriverForClientMode();
+ verify(mWifiVendorHal).startVendorHalSta();
+ verify(mWificondControl).setupInterfaceForClientMode(WIFI_IFACE_NAME);
}
/**
- * Verifies that setupDriverForClientMode() does not call start vendor HAL when it is not
- * supported and calls underlying WificondControl setup.
+ * Verifies that setupInterfaceForClientMode(WIFI_IFACE_NAME) does not call start vendor HAL
+ * when it is not supported and calls underlying WificondControl setup.
*/
@Test
public void testSetupDriverForClientModeWithNoVendorHal() {
when(mWifiVendorHal.isVendorHalSupported()).thenReturn(false);
IClientInterface clientInterface = mock(IClientInterface.class);
- when(mWificondControl.setupDriverForClientMode()).thenReturn(clientInterface);
+ when(mWificondControl.setupInterfaceForClientMode(WIFI_IFACE_NAME))
+ .thenReturn(clientInterface);
- Pair<Integer, IClientInterface> statusAndClientInterface = mWifiNative.setupForClientMode();
+ Pair<Integer, IClientInterface> statusAndClientInterface =
+ mWifiNative.setupForClientMode(WIFI_IFACE_NAME);
assertTrue(WifiNative.SETUP_SUCCESS == statusAndClientInterface.first);
assertEquals(clientInterface, statusAndClientInterface.second);
- verify(mWifiVendorHal, never()).startVendorHal(anyBoolean());
- verify(mWificondControl).setupDriverForClientMode();
+ verify(mWifiVendorHal, never()).startVendorHalSta();
+ verify(mWificondControl).setupInterfaceForClientMode(WIFI_IFACE_NAME);
}
/**
- * Verifies that setupDriverForClientMode() returns null when underlying WificondControl
- * call fails.
+ * Verifies that setupInterfaceForClientMode(WIFI_IFACE_NAME) returns null when underlying
+ * WificondControl call fails.
*/
@Test
public void testSetupDriverForClientModeWificondError() {
- when(mWificondControl.setupDriverForClientMode()).thenReturn(null);
+ when(mWificondControl.setupInterfaceForClientMode(WIFI_IFACE_NAME)).thenReturn(null);
- Pair<Integer, IClientInterface> statusAndClientInterface = mWifiNative.setupForClientMode();
+ Pair<Integer, IClientInterface> statusAndClientInterface =
+ mWifiNative.setupForClientMode(WIFI_IFACE_NAME);
assertTrue(WifiNative.SETUP_FAILURE_WIFICOND == statusAndClientInterface.first);
assertEquals(null, statusAndClientInterface.second);
- verify(mWifiVendorHal).startVendorHal(eq(true));
- verify(mWificondControl).setupDriverForClientMode();
+ verify(mWifiVendorHal).startVendorHalSta();
+ verify(mWificondControl).setupInterfaceForClientMode(WIFI_IFACE_NAME);
}
/**
- * Verifies that setupDriverForClientMode() returns null when underlying Hal call fails.
+ * Verifies that setupInterfaceForClientMode(WIFI_IFACE_NAME) returns null when underlying Hal
+ * call fails.
*/
@Test
public void testSetupDriverForClientModeHalError() {
- when(mWifiVendorHal.startVendorHal(anyBoolean())).thenReturn(false);
+ when(mWifiVendorHal.startVendorHalSta()).thenReturn(false);
- Pair<Integer, IClientInterface> statusAndClientInterface = mWifiNative.setupForClientMode();
+ Pair<Integer, IClientInterface> statusAndClientInterface =
+ mWifiNative.setupForClientMode(WIFI_IFACE_NAME);
assertTrue(WifiNative.SETUP_FAILURE_HAL == statusAndClientInterface.first);
assertEquals(null, statusAndClientInterface.second);
- verify(mWifiVendorHal).startVendorHal(eq(true));
- verify(mWificondControl, never()).setupDriverForClientMode();
+ verify(mWifiVendorHal).startVendorHalSta();
+ verify(mWificondControl, never()).setupInterfaceForClientMode(WIFI_IFACE_NAME);
}
/**
- * Verifies that setupDriverForSoftApMode() calls underlying WificondControl.
+ * Verifies that setupInterfaceForSoftApMode(WIFI_IFACE_NAME) calls underlying WificondControl.
*/
@Test
public void testSetupDriverForSoftApMode() {
IApInterface apInterface = mock(IApInterface.class);
- when(mWificondControl.setupDriverForSoftApMode()).thenReturn(apInterface);
+ when(mWificondControl.setupInterfaceForSoftApMode(WIFI_IFACE_NAME)).thenReturn(apInterface);
- Pair<Integer, IApInterface> statusAndApInterface = mWifiNative.setupForSoftApMode();
+ Pair<Integer, IApInterface> statusAndApInterface =
+ mWifiNative.setupForSoftApMode(WIFI_IFACE_NAME);
assertTrue(WifiNative.SETUP_SUCCESS == statusAndApInterface.first);
assertEquals(apInterface, statusAndApInterface.second);
- verify(mWifiVendorHal).startVendorHal(eq(false));
- verify(mWificondControl).setupDriverForSoftApMode();
+ verify(mWifiVendorHal).startVendorHalAp();
+ verify(mWificondControl).setupInterfaceForSoftApMode(WIFI_IFACE_NAME);
}
/**
- * Verifies that setupDriverForClientMode() does not call start vendor HAL when it is not
- * supported and calls underlying WificondControl setup.
+ * Verifies that setupInterfaceForClientMode(WIFI_IFACE_NAME) does not call start vendor HAL
+ * when it is not supported and calls underlying WificondControl setup.
*/
@Test
public void testSetupDriverForSoftApModeWithNoVendorHal() {
when(mWifiVendorHal.isVendorHalSupported()).thenReturn(false);
IApInterface apInterface = mock(IApInterface.class);
- when(mWificondControl.setupDriverForSoftApMode()).thenReturn(apInterface);
+ when(mWificondControl.setupInterfaceForSoftApMode(WIFI_IFACE_NAME)).thenReturn(apInterface);
- Pair<Integer, IApInterface> statusAndApInterface = mWifiNative.setupForSoftApMode();
+ Pair<Integer, IApInterface> statusAndApInterface =
+ mWifiNative.setupForSoftApMode(WIFI_IFACE_NAME);
assertTrue(WifiNative.SETUP_SUCCESS == statusAndApInterface.first);
assertEquals(apInterface, statusAndApInterface.second);
- verify(mWifiVendorHal, never()).startVendorHal(anyBoolean());
- verify(mWificondControl).setupDriverForSoftApMode();
+ verify(mWifiVendorHal, never()).startVendorHalAp();
+ verify(mWificondControl).setupInterfaceForSoftApMode(WIFI_IFACE_NAME);
}
/**
- * Verifies that setupDriverForSoftApMode() returns null when underlying WificondControl
- * call fails.
+ * Verifies that setupInterfaceForSoftApMode(WIFI_IFACE_NAME) returns null when underlying
+ * WificondControl call fails.
*/
@Test
public void testSetupDriverForSoftApModeWificondError() {
- when(mWificondControl.setupDriverForSoftApMode()).thenReturn(null);
+ when(mWificondControl.setupInterfaceForSoftApMode(WIFI_IFACE_NAME)).thenReturn(null);
- Pair<Integer, IApInterface> statusAndApInterface = mWifiNative.setupForSoftApMode();
+ Pair<Integer, IApInterface> statusAndApInterface =
+ mWifiNative.setupForSoftApMode(WIFI_IFACE_NAME);
assertTrue(WifiNative.SETUP_FAILURE_WIFICOND == statusAndApInterface.first);
assertEquals(null, statusAndApInterface.second);
- verify(mWifiVendorHal).startVendorHal(eq(false));
- verify(mWificondControl).setupDriverForSoftApMode();
+ verify(mWifiVendorHal).startVendorHalAp();
+ verify(mWificondControl).setupInterfaceForSoftApMode(WIFI_IFACE_NAME);
}
/**
- * Verifies that setupDriverForSoftApMode() returns null when underlying Hal call fails.
+ * Verifies that setupInterfaceForSoftApMode(WIFI_IFACE_NAME) returns null when underlying Hal
+ * call fails.
*/
@Test
public void testSetupDriverForSoftApModeHalError() {
- when(mWifiVendorHal.startVendorHal(anyBoolean())).thenReturn(false);
+ when(mWifiVendorHal.startVendorHalAp()).thenReturn(false);
- Pair<Integer, IApInterface> statusAndApInterface = mWifiNative.setupForSoftApMode();
+ Pair<Integer, IApInterface> statusAndApInterface =
+ mWifiNative.setupForSoftApMode(WIFI_IFACE_NAME);
assertTrue(WifiNative.SETUP_FAILURE_HAL == statusAndApInterface.first);
assertEquals(null, statusAndApInterface.second);
- verify(mWifiVendorHal).startVendorHal(eq(false));
- verify(mWificondControl, never()).setupDriverForSoftApMode();
+ verify(mWifiVendorHal).startVendorHalAp();
+ verify(mWificondControl, never()).setupInterfaceForSoftApMode(WIFI_IFACE_NAME);
}
/**
@@ -657,10 +670,11 @@
*/
@Test
public void testSignalPoll() throws Exception {
- when(mWificondControl.signalPoll()).thenReturn(SIGNAL_POLL_RESULT);
+ when(mWificondControl.signalPoll(WIFI_IFACE_NAME))
+ .thenReturn(SIGNAL_POLL_RESULT);
assertEquals(SIGNAL_POLL_RESULT, mWifiNative.signalPoll());
- verify(mWificondControl).signalPoll();
+ verify(mWificondControl).signalPoll(WIFI_IFACE_NAME);
}
/**
@@ -668,10 +682,11 @@
*/
@Test
public void testGetTxPacketCounters() throws Exception {
- when(mWificondControl.getTxPacketCounters()).thenReturn(PACKET_COUNTERS_RESULT);
+ when(mWificondControl.getTxPacketCounters(WIFI_IFACE_NAME))
+ .thenReturn(PACKET_COUNTERS_RESULT);
assertEquals(PACKET_COUNTERS_RESULT, mWifiNative.getTxPacketCounters());
- verify(mWificondControl).getTxPacketCounters();
+ verify(mWificondControl).getTxPacketCounters(WIFI_IFACE_NAME);
}
/**
@@ -680,7 +695,8 @@
@Test
public void testScan() throws Exception {
mWifiNative.scan(SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_SET);
- verify(mWificondControl).scan(SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_SET);
+ verify(mWificondControl).scan(
+ WIFI_IFACE_NAME, SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_SET);
}
/**
@@ -689,7 +705,8 @@
@Test
public void testStartPnoScan() throws Exception {
mWifiNative.startPnoScan(TEST_PNO_SETTINGS);
- verify(mWificondControl).startPnoScan(TEST_PNO_SETTINGS);
+ verify(mWificondControl).startPnoScan(
+ WIFI_IFACE_NAME, TEST_PNO_SETTINGS);
}
/**
@@ -698,7 +715,7 @@
@Test
public void testStopPnoScan() throws Exception {
mWifiNative.stopPnoScan();
- verify(mWificondControl).stopPnoScan();
+ verify(mWificondControl).stopPnoScan(WIFI_IFACE_NAME);
}
/**
@@ -709,8 +726,8 @@
WifiConfiguration config = mock(WifiConfiguration.class);
mWifiNative.connectToNetwork(config);
// connectToNetwork() should abort ongoing scan before connection.
- verify(mWificondControl).abortScan();
- verify(mStaIfaceHal).connectToNetwork(config);
+ verify(mWificondControl).abortScan(WIFI_IFACE_NAME);
+ verify(mStaIfaceHal).connectToNetwork(WIFI_IFACE_NAME, config);
}
/**
@@ -721,8 +738,7 @@
WifiConfiguration config = mock(WifiConfiguration.class);
mWifiNative.roamToNetwork(config);
// roamToNetwork() should abort ongoing scan before connection.
- verify(mWificondControl).abortScan();
- verify(mStaIfaceHal).roamToNetwork(config);
+ verify(mWificondControl).abortScan(WIFI_IFACE_NAME);
+ verify(mStaIfaceHal).roamToNetwork(WIFI_IFACE_NAME, config);
}
-
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiScoreReportTest.java b/tests/wifitests/src/com/android/server/wifi/WifiScoreReportTest.java
index 6f01c8e..022d5dd 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiScoreReportTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiScoreReportTest.java
@@ -17,10 +17,13 @@
package com.android.server.wifi;
import static org.junit.Assert.assertTrue;
+import static org.mockito.AdditionalAnswers.answerVoid;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.atMost;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -240,11 +243,16 @@
@Test
public void giveUpOnBadRssiAggressively() throws Exception {
mAggr = 1;
- mWifiInfo.setRssi(-83);
- mWifiScoreReport.calculateAndReportScore(mWifiInfo, mNetworkAgent, mAggr, mWifiMetrics);
+ String oops = "giveUpOnBadRssiAggressively";
+ for (int rssi = -60; rssi >= -83; rssi -= 1) {
+ mWifiInfo.setRssi(rssi);
+ oops += " " + mClock.mWallClockMillis + "," + rssi;
+ mWifiScoreReport.calculateAndReportScore(mWifiInfo, mNetworkAgent, mAggr, mWifiMetrics);
+ oops += ":" + mWifiInfo.score;
+ }
int score = mWifiInfo.score;
verify(mNetworkAgent, atLeast(1)).sendNetworkScore(score);
- assertTrue(score < CELLULAR_THRESHOLD_SCORE);
+ assertTrue(oops, score < CELLULAR_THRESHOLD_SCORE);
}
/**
@@ -261,6 +269,21 @@
}
/**
+ * This setup causes some reports to be generated when println
+ * methods are called, to check for "concurrent" modification
+ * errors.
+ */
+ private void setupToGenerateAReportWhenPrintlnIsCalled() {
+ int[] counter = new int[1];
+ doAnswer(answerVoid((String line) -> {
+ if (counter[0]++ < 3) {
+ mWifiScoreReport.calculateAndReportScore(
+ mWifiInfo, mNetworkAgent, mAggr, mWifiMetrics);
+ }
+ })).when(mPrintWriter).println(anyString());
+ }
+
+ /**
* Test data logging
*/
@Test
@@ -276,8 +299,9 @@
mWifiInfo.rxSuccessRate = 0.3 + i;
mWifiScoreReport.calculateAndReportScore(mWifiInfo, mNetworkAgent, mAggr, mWifiMetrics);
}
+ setupToGenerateAReportWhenPrintlnIsCalled();
mWifiScoreReport.dump(null, mPrintWriter, null);
- verify(mPrintWriter, atLeast(11)).println(anyString());
+ verify(mPrintWriter, times(11)).println(anyString());
}
/**
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java b/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java
index e43bdc2..ea81d53 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java
@@ -64,6 +64,8 @@
import android.net.wifi.WifiEnterpriseConfig;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiManager.LocalOnlyHotspotCallback;
+import android.net.wifi.hotspot2.IProvisioningCallback;
+import android.net.wifi.hotspot2.OsuProvider;
import android.net.wifi.hotspot2.PasspointConfiguration;
import android.os.Handler;
import android.os.HandlerThread;
@@ -83,10 +85,10 @@
import com.android.internal.util.AsyncChannel;
import com.android.server.wifi.WifiServiceImpl.LocalOnlyRequestorCallback;
+import com.android.server.wifi.hotspot2.PasspointProvisioningTestUtil;
import com.android.server.wifi.util.WifiAsyncChannel;
import com.android.server.wifi.util.WifiPermissionsUtil;
-
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
@@ -119,6 +121,7 @@
private static final int TEST_PID = 6789;
private static final int TEST_PID2 = 9876;
private static final String WIFI_IFACE_NAME = "wlan0";
+ private static final String TEST_COUNTRY_CODE = "US";
private WifiServiceImpl mWifiServiceImpl;
private TestLooper mLooper;
@@ -127,6 +130,7 @@
private Messenger mAppMessenger;
private int mPid;
private int mPid2 = Process.myPid();
+ private OsuProvider mOsuProvider;
final ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverCaptor =
ArgumentCaptor.forClass(BroadcastReceiver.class);
@@ -139,6 +143,7 @@
@Mock Context mContext;
@Mock WifiInjector mWifiInjector;
+ @Mock WifiCountryCode mWifiCountryCode;
@Mock Clock mClock;
@Mock WifiController mWifiController;
@Mock WifiTrafficPoller mWifiTrafficPoller;
@@ -163,6 +168,7 @@
@Mock IBinder mAppBinder;
@Mock LocalOnlyHotspotRequestInfo mRequestInfo;
@Mock LocalOnlyHotspotRequestInfo mRequestInfo2;
+ @Mock IProvisioningCallback mProvisioningCallback;
@Spy FakeWifiLog mLog;
@@ -236,6 +242,7 @@
when(mRequestInfo.getPid()).thenReturn(mPid);
when(mRequestInfo2.getPid()).thenReturn(mPid2);
when(mWifiInjector.getUserManager()).thenReturn(mUserManager);
+ when(mWifiInjector.getWifiCountryCode()).thenReturn(mWifiCountryCode);
when(mWifiInjector.getWifiController()).thenReturn(mWifiController);
when(mWifiInjector.getWifiMetrics()).thenReturn(mWifiMetrics);
when(mWifiInjector.getWifiStateMachine()).thenReturn(mWifiStateMachine);
@@ -277,6 +284,12 @@
when(mWifiInjector.getWifiPermissionsUtil()).thenReturn(mWifiPermissionsUtil);
when(mWifiInjector.getWifiSettingsStore()).thenReturn(mSettingsStore);
when(mWifiInjector.getClock()).thenReturn(mClock);
+ when(mWifiStateMachine.syncStartSubscriptionProvisioning(anyInt(),
+ any(OsuProvider.class), any(IProvisioningCallback.class), any())).thenReturn(true);
+ when(mPackageManager.hasSystemFeature(
+ PackageManager.FEATURE_WIFI_PASSPOINT)).thenReturn(true);
+ // Create an OSU provider that can be provisioned via an open OSU AP
+ mOsuProvider = PasspointProvisioningTestUtil.generateOsuProvider(true);
mWifiServiceImpl = new WifiServiceImpl(mContext, mWifiInjector, mAsyncChannel);
mWifiServiceImpl.setWifiHandlerLogForTest(mLog);
}
@@ -586,94 +599,6 @@
}
/**
- * Verify setWifiApEnabled works with the correct permissions and a null config.
- */
- @Test
- public void testSetWifiApEnabledWithProperPermissionsWithNullConfig() {
- when(mWifiPermissionsUtil.checkConfigOverridePermission(anyInt())).thenReturn(true);
- when(mUserManager.hasUserRestriction(eq(UserManager.DISALLOW_CONFIG_TETHERING)))
- .thenReturn(false);
- mWifiServiceImpl.setWifiApEnabled(null, true);
- verify(mWifiController)
- .sendMessage(eq(CMD_SET_AP), eq(1), eq(0), mSoftApModeConfigCaptor.capture());
- assertNull(mSoftApModeConfigCaptor.getValue().getWifiConfiguration());
- }
-
- /**
- * Verify setWifiApEnabled works with correct permissions and a valid config.
- *
- * TODO: should really validate that ap configs have a set of basic config settings b/37280779
- */
- @Test
- public void testSetWifiApEnabledWithProperPermissionsWithValidConfig() {
- when(mWifiPermissionsUtil.checkConfigOverridePermission(anyInt())).thenReturn(true);
- when(mUserManager.hasUserRestriction(eq(UserManager.DISALLOW_CONFIG_TETHERING)))
- .thenReturn(false);
- WifiConfiguration apConfig = new WifiConfiguration();
- mWifiServiceImpl.setWifiApEnabled(apConfig, true);
- verify(mWifiController).sendMessage(
- eq(CMD_SET_AP), eq(1), eq(0), mSoftApModeConfigCaptor.capture());
- assertEquals(apConfig, mSoftApModeConfigCaptor.getValue().getWifiConfiguration());
- }
-
- /**
- * Verify setWifiApEnabled when disabling softap with correct permissions sends the correct
- * message to WifiController.
- */
- @Test
- public void testSetWifiApEnabledFalseWithProperPermissionsWithNullConfig() {
- when(mWifiPermissionsUtil.checkConfigOverridePermission(anyInt())).thenReturn(true);
- when(mUserManager.hasUserRestriction(eq(UserManager.DISALLOW_CONFIG_TETHERING)))
- .thenReturn(false);
- mWifiServiceImpl.setWifiApEnabled(null, false);
- verify(mWifiController)
- .sendMessage(eq(CMD_SET_AP), eq(0), eq(0), mSoftApModeConfigCaptor.capture());
- assertNull(mSoftApModeConfigCaptor.getValue().getWifiConfiguration());
- }
-
- /**
- * setWifiApEnabled should fail if the provided config is not valid.
- */
- @Test
- public void testSetWifiApEnabledWithProperPermissionInvalidConfigFails() {
- when(mWifiPermissionsUtil.checkConfigOverridePermission(anyInt())).thenReturn(true);
- when(mUserManager.hasUserRestriction(eq(UserManager.DISALLOW_CONFIG_TETHERING)))
- .thenReturn(false);
- // mApConfig is a mock and the values are not set - triggering the invalid config. Testing
- // will be improved when we actually do test softap configs in b/37280779
- mWifiServiceImpl.setWifiApEnabled(mApConfig, true);
- verify(mWifiController, never())
- .sendMessage(eq(CMD_SET_AP), eq(1), eq(0), any(SoftApModeConfiguration.class));
- }
-
- /**
- * setWifiApEnabled should throw a security exception when the caller does not have the correct
- * permissions.
- */
- @Test(expected = SecurityException.class)
- public void testSetWifiApEnabledThrowsSecurityExceptionWithoutConfigOverridePermission()
- throws Exception {
- doThrow(new SecurityException()).when(mContext)
- .enforceCallingOrSelfPermission(eq(android.Manifest.permission.CHANGE_WIFI_STATE),
- eq("WifiService"));
- mWifiServiceImpl.setWifiApEnabled(null, true);
- }
-
- /**
- * setWifiApEnabled should throw a SecurityException when disallow tethering is set for the
- * user.
- */
- @Test(expected = SecurityException.class)
- public void testSetWifiApEnabledThrowsSecurityExceptionWithDisallowTethering()
- throws Exception {
- when(mWifiPermissionsUtil.checkConfigOverridePermission(anyInt())).thenReturn(true);
- when(mUserManager.hasUserRestriction(eq(UserManager.DISALLOW_CONFIG_TETHERING)))
- .thenReturn(true);
- mWifiServiceImpl.setWifiApEnabled(null, true);
-
- }
-
- /**
* Verify caller with proper permission can call startSoftAp.
*/
@Test
@@ -1600,6 +1525,60 @@
}
/**
+ * Verify that the call to startSubscriptionProvisioning is redirected to the Passpoint
+ * specific API startSubscriptionProvisioning when the caller has the right permissions.
+ */
+ @Test
+ public void testStartSubscriptionProvisioningWithPermission() throws Exception {
+ mWifiServiceImpl.startSubscriptionProvisioning(mOsuProvider, mProvisioningCallback);
+ verify(mWifiStateMachine).syncStartSubscriptionProvisioning(anyInt(),
+ eq(mOsuProvider), eq(mProvisioningCallback), any());
+ }
+
+ /**
+ * Verify that the call to startSubscriptionProvisioning is not directed to the Passpoint
+ * specific API startSubscriptionProvisioning when the feature is not supported.
+ */
+ @Test(expected = UnsupportedOperationException.class)
+ public void testStartSubscriptionProvisioniningPasspointUnsupported() throws Exception {
+ when(mPackageManager.hasSystemFeature(
+ PackageManager.FEATURE_WIFI_PASSPOINT)).thenReturn(false);
+ mWifiServiceImpl.startSubscriptionProvisioning(mOsuProvider, mProvisioningCallback);
+ }
+
+ /**
+ * Verify that the call to startSubscriptionProvisioning is not redirected to the Passpoint
+ * specific API startSubscriptionProvisioning when the caller provides invalid arguments
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testStartSubscriptionProvisioningWithInvalidProvider() throws Exception {
+ mWifiServiceImpl.startSubscriptionProvisioning(null, mProvisioningCallback);
+ }
+
+
+ /**
+ * Verify that the call to startSubscriptionProvisioning is not redirected to the Passpoint
+ * specific API startSubscriptionProvisioning when the caller provides invalid callback
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testStartSubscriptionProvisioningWithInvalidCallback() throws Exception {
+ mWifiServiceImpl.startSubscriptionProvisioning(mOsuProvider, null);
+ }
+
+ /**
+ * Verify that the call to startSubscriptionProvisioning is not redirected to the Passpoint
+ * specific API startSubscriptionProvisioning when the caller doesn't have NETWORK_SETTINGS
+ * permissions.
+ */
+ @Test(expected = SecurityException.class)
+ public void testStartSubscriptionProvisioningWithoutPermission() throws Exception {
+ doThrow(new SecurityException()).when(mContext)
+ .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_SETTINGS),
+ eq("WifiService"));
+ mWifiServiceImpl.startSubscriptionProvisioning(mOsuProvider, mProvisioningCallback);
+ }
+
+ /**
* Verify that a call to {@link WifiServiceImpl#restoreBackupData(byte[])} is only allowed from
* callers with the signature only NETWORK_SETTINGS permission.
*/
@@ -1640,6 +1619,31 @@
}
/**
+ * Verify that a call to {@link WifiServiceImpl#enableVerboseLogging(int)} is allowed from
+ * callers with the signature only NETWORK_SETTINGS permission.
+ */
+ public void testEnableVerboseLoggingWithNetworkSettingsPermission() {
+ doNothing().when(mContext)
+ .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_SETTINGS),
+ eq("WifiService"));
+ mWifiServiceImpl.enableVerboseLogging(1);
+ verify(mWifiStateMachine).enableVerboseLogging(anyInt());
+ }
+
+ /**
+ * Verify that a call to {@link WifiServiceImpl#enableVerboseLogging(int)} is not allowed from
+ * callers without the signature only NETWORK_SETTINGS permission.
+ */
+ @Test(expected = SecurityException.class)
+ public void testEnableVerboseLoggingWithNoNetworkSettingsPermission() {
+ doThrow(new SecurityException()).when(mContext)
+ .enforceCallingOrSelfPermission(eq(android.Manifest.permission.NETWORK_SETTINGS),
+ eq("WifiService"));
+ mWifiServiceImpl.enableVerboseLogging(1);
+ verify(mWifiStateMachine, never()).enableVerboseLogging(anyInt());
+ }
+
+ /**
* Helper to test handling of async messages by wifi service when the message comes from an
* app without {@link android.Manifest.permission#CHANGE_WIFI_STATE} permission.
*/
@@ -1817,4 +1821,27 @@
verifyAsyncChannelMessageHandlingWithChangePermisson(
WifiManager.RSSI_PKTCNT_FETCH, new Object());
}
+
+ /**
+ * Verify that setCountryCode() calls WifiCountryCode object on succeess.
+ */
+ @Test
+ public void testSetCountryCode() throws Exception {
+ mWifiServiceImpl.setCountryCode(TEST_COUNTRY_CODE);
+ verify(mWifiCountryCode).setCountryCode(TEST_COUNTRY_CODE);
+ }
+
+ /**
+ * Verify that setCountryCode() fails and doesn't call WifiCountryCode object
+ * if the caller doesn't have CONNECTIVITY_INTERNAL permission.
+ */
+ @Test(expected = SecurityException.class)
+ public void testSetCountryCodeFailsWithoutConnectivityInternalPermission() throws Exception {
+ doThrow(new SecurityException()).when(mContext)
+ .enforceCallingOrSelfPermission(
+ eq(android.Manifest.permission.CONNECTIVITY_INTERNAL),
+ eq("ConnectivityService"));
+ mWifiServiceImpl.setCountryCode(TEST_COUNTRY_CODE);
+ verify(mWifiCountryCode, never()).setCountryCode(TEST_COUNTRY_CODE);
+ }
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiStateMachinePrimeTest.java b/tests/wifitests/src/com/android/server/wifi/WifiStateMachinePrimeTest.java
index 49c7d18..2e26769 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiStateMachinePrimeTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiStateMachinePrimeTest.java
@@ -50,8 +50,10 @@
private static final String CLIENT_MODE_ACTIVE_STATE_STRING = "ClientModeActiveState";
private static final String SCAN_ONLY_MODE_ACTIVE_STATE_STRING = "ScanOnlyModeActiveState";
private static final String SOFT_AP_MODE_ACTIVE_STATE_STRING = "SoftAPModeActiveState";
+ private static final String WIFI_IFACE_NAME = "mockWlan";
@Mock WifiInjector mWifiInjector;
+ @Mock WifiNative mWifiNative;
@Mock WifiApConfigStore mWifiApConfigStore;
TestLooper mLooper;
@Mock IWificond mWificond;
@@ -71,7 +73,8 @@
MockitoAnnotations.initMocks(this);
mLooper = new TestLooper();
- mWifiInjector = mock(WifiInjector.class);
+ when(mWifiInjector.getWifiNative()).thenReturn(mWifiNative);
+ when(mWifiNative.getInterfaceName()).thenReturn(WIFI_IFACE_NAME);
mWifiStateMachinePrime = createWifiStateMachinePrime();
}
@@ -89,7 +92,8 @@
}
private void enterSoftApActiveMode() throws Exception {
- enterSoftApActiveMode(null);
+ enterSoftApActiveMode(
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null));
}
/**
@@ -97,10 +101,11 @@
*
* This method puts the test object into the correct state and verifies steps along the way.
*/
- private void enterSoftApActiveMode(WifiConfiguration wifiConfig) throws Exception {
+ private void enterSoftApActiveMode(SoftApModeConfiguration softApConfig) throws Exception {
String fromState = mWifiStateMachinePrime.getCurrentMode();
when(mWifiInjector.makeWificond()).thenReturn(mWificond);
- when(mWificond.createApInterface()).thenReturn(mApInterface);
+ when(mWificond.createApInterface(WIFI_IFACE_NAME)).thenReturn(mApInterface);
+ when(mApInterface.getInterfaceName()).thenReturn(WIFI_IFACE_NAME);
doAnswer(
new Answer<Object>() {
public SoftApManager answer(InvocationOnMock invocation) {
@@ -108,14 +113,16 @@
assertEquals(mNMService, (INetworkManagementService) args[0]);
mSoftApListener = (SoftApManager.Listener) args[1];
assertEquals(mApInterface, (IApInterface) args[2]);
- assertEquals(wifiConfig, (WifiConfiguration) args[3]);
+ assertEquals(WIFI_IFACE_NAME, (String) args[3]);
+ assertEquals(softApConfig, (SoftApModeConfiguration) args[4]);
return mSoftApManager;
}
}).when(mWifiInjector).makeSoftApManager(any(INetworkManagementService.class),
any(SoftApManager.Listener.class),
any(IApInterface.class),
+ anyString(),
any());
- mWifiStateMachinePrime.enterSoftAPMode(wifiConfig);
+ mWifiStateMachinePrime.enterSoftAPMode(softApConfig);
mLooper.dispatchAll();
Log.e("WifiStateMachinePrimeTest", "check fromState: " + fromState);
if (!fromState.equals(WIFI_DISABLED_STATE_STRING)) {
@@ -183,7 +190,8 @@
public void testDisableWifiFromSoftApModeState() throws Exception {
// Use a failure getting wificond to stay in the SoftAPModeState
when(mWifiInjector.makeWificond()).thenReturn(null);
- mWifiStateMachinePrime.enterSoftAPMode(null);
+ mWifiStateMachinePrime.enterSoftAPMode(
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null));
mLooper.dispatchAll();
assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
@@ -218,7 +226,8 @@
@Test
public void testWificondNullWhenSwitchingToApMode() throws Exception {
when(mWifiInjector.makeWificond()).thenReturn(null);
- mWifiStateMachinePrime.enterSoftAPMode(null);
+ mWifiStateMachinePrime.enterSoftAPMode(
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null));
mLooper.dispatchAll();
assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
}
@@ -232,22 +241,24 @@
@Test
public void testAPInterfaceFailedWhenSwitchingToApMode() throws Exception {
when(mWifiInjector.makeWificond()).thenReturn(mWificond);
- when(mWificond.createApInterface()).thenReturn(null);
- mWifiStateMachinePrime.enterSoftAPMode(null);
+ when(mWificond.createApInterface(WIFI_IFACE_NAME)).thenReturn(null);
+ mWifiStateMachinePrime.enterSoftAPMode(
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null));
mLooper.dispatchAll();
assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
}
/**
- * Test that we do can enter the SoftApModeActiveState if we are already in the SoftApModeState.
+ * Test that we do enter the SoftApModeActiveState if we are already in the SoftApModeState.
* Expectations: We should exit the current SoftApModeState and re-enter before successfully
* entering the SoftApModeActiveState.
*/
@Test
public void testEnterSoftApModeActiveWhenAlreadyInSoftApMode() throws Exception {
when(mWifiInjector.makeWificond()).thenReturn(mWificond);
- when(mWificond.createApInterface()).thenReturn(null);
- mWifiStateMachinePrime.enterSoftAPMode(null);
+ when(mWificond.createApInterface(WIFI_IFACE_NAME)).thenReturn(null);
+ mWifiStateMachinePrime.enterSoftAPMode(
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null));
mLooper.dispatchAll();
assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
@@ -294,7 +305,9 @@
public void testConfigIsPassedToWifiInjector() throws Exception {
WifiConfiguration config = new WifiConfiguration();
config.SSID = "ThisIsAConfig";
- enterSoftApActiveMode(config);
+ SoftApModeConfiguration softApConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config);
+ enterSoftApActiveMode(softApConfig);
}
/**
@@ -307,7 +320,7 @@
*/
@Test
public void testNullConfigIsPassedToWifiInjector() throws Exception {
- enterSoftApActiveMode(null);
+ enterSoftApActiveMode();
}
/**
@@ -316,22 +329,25 @@
* config - this second call should use the correct config.
*/
@Test
- public void testNullConfigFailsSecondCallWithConfigSuccessful() throws Exception {
+ public void testNullApModeConfigFails() throws Exception {
when(mWifiInjector.makeWificond()).thenReturn(mWificond);
- when(mWificond.createApInterface()).thenReturn(null);
- mWifiStateMachinePrime.enterSoftAPMode(null);
+ when(mWificond.createApInterface(WIFI_IFACE_NAME)).thenReturn(null);
+ mWifiStateMachinePrime.enterSoftAPMode(
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null));
mLooper.dispatchAll();
assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
WifiConfiguration config = new WifiConfiguration();
config.SSID = "ThisIsAConfig";
- enterSoftApActiveMode(config);
+ SoftApModeConfiguration softApConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config);
+ enterSoftApActiveMode(softApConfig);
}
/**
- * Test that a failed call to start softap with a valid config has the config saved for future
- * calls to enable softap.
+ * Test that a failed call to start softap with a valid config does not persist the ap
+ * configuration to the WifiApConfigStore.
*
- * Expectations: A call to start SoftAPMode with a config should write out the config if we
+ * Expectations: A call to start SoftAPMode with a config should not write out the config if we
* did not create a SoftApManager.
*/
@Test
@@ -340,10 +356,12 @@
when(mWifiInjector.getWifiApConfigStore()).thenReturn(mWifiApConfigStore);
WifiConfiguration config = new WifiConfiguration();
config.SSID = "ThisIsAConfig";
- mWifiStateMachinePrime.enterSoftAPMode(config);
+ SoftApModeConfiguration softApConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config);
+ mWifiStateMachinePrime.enterSoftAPMode(softApConfig);
mLooper.dispatchAll();
assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
- verify(mWifiApConfigStore).setApConfiguration(eq(config));
+ verify(mWifiApConfigStore, never()).setApConfiguration(eq(config));
}
/**
@@ -354,27 +372,34 @@
@Test
public void testStartSoftApModeTwiceWithTwoConfigs() throws Exception {
when(mWifiInjector.makeWificond()).thenReturn(mWificond);
- when(mWificond.createApInterface()).thenReturn(mApInterface);
+ when(mWificond.createApInterface(WIFI_IFACE_NAME)).thenReturn(mApInterface);
+ when(mApInterface.getInterfaceName()).thenReturn(WIFI_IFACE_NAME);
when(mWifiInjector.getWifiApConfigStore()).thenReturn(mWifiApConfigStore);
WifiConfiguration config1 = new WifiConfiguration();
config1.SSID = "ThisIsAConfig";
+ SoftApModeConfiguration softApConfig1 =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config1);
WifiConfiguration config2 = new WifiConfiguration();
config2.SSID = "ThisIsASecondConfig";
+ SoftApModeConfiguration softApConfig2 =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config2);
when(mWifiInjector.makeSoftApManager(any(INetworkManagementService.class),
any(SoftApManager.Listener.class),
any(IApInterface.class),
- eq(config1)))
+ anyString(),
+ eq(softApConfig1)))
.thenReturn(mSoftApManager);
when(mWifiInjector.makeSoftApManager(any(INetworkManagementService.class),
any(SoftApManager.Listener.class),
any(IApInterface.class),
- eq(config2)))
+ anyString(),
+ eq(softApConfig2)))
.thenReturn(mSoftApManager);
- mWifiStateMachinePrime.enterSoftAPMode(config1);
- mWifiStateMachinePrime.enterSoftAPMode(config2);
+ mWifiStateMachinePrime.enterSoftAPMode(softApConfig1);
+ mWifiStateMachinePrime.enterSoftAPMode(softApConfig2);
mLooper.dispatchAll();
assertEquals(SOFT_AP_MODE_ACTIVE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java b/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
index 090224e..ad5aa43 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
@@ -63,6 +63,8 @@
import android.net.wifi.WifiScanner;
import android.net.wifi.WifiSsid;
import android.net.wifi.WpsInfo;
+import android.net.wifi.hotspot2.IProvisioningCallback;
+import android.net.wifi.hotspot2.OsuProvider;
import android.net.wifi.hotspot2.PasspointConfiguration;
import android.net.wifi.hotspot2.pps.HomeSp;
import android.net.wifi.p2p.IWifiP2pManager;
@@ -80,7 +82,6 @@
import android.os.Messenger;
import android.os.PowerManager;
import android.os.Process;
-import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.test.TestLooper;
@@ -102,6 +103,7 @@
import com.android.internal.util.StateMachine;
import com.android.server.wifi.hotspot2.NetworkDetail;
import com.android.server.wifi.hotspot2.PasspointManager;
+import com.android.server.wifi.hotspot2.PasspointProvisioningTestUtil;
import com.android.server.wifi.p2p.WifiP2pServiceImpl;
import com.android.server.wifi.util.WifiPermissionsUtil;
@@ -334,6 +336,7 @@
IpClient.Callback mIpClientCallback;
PhoneStateListener mPhoneStateListener;
NetworkRequest mDefaultNetworkRequest;
+ OsuProvider mOsuProvider;
final ArgumentCaptor<SoftApManager.Listener> mSoftApManagerListenerCaptor =
ArgumentCaptor.forClass(SoftApManager.Listener.class);
@@ -352,8 +355,6 @@
@Mock IWificond mWificond;
@Mock IApInterface mApInterface;
@Mock IClientInterface mClientInterface;
- @Mock IBinder mApInterfaceBinder;
- @Mock IBinder mClientInterfaceBinder;
@Mock IBinder mPackageManagerBinder;
@Mock WifiConfigManager mWifiConfigManager;
@Mock WifiNative mWifiNative;
@@ -370,6 +371,8 @@
@Mock ScanDetailCache mScanDetailCache;
@Mock BaseWifiDiagnostics mWifiDiagnostics;
@Mock ConnectivityManager mConnectivityManager;
+ @Mock IProvisioningCallback mProvisioningCallback;
+ @Mock HandlerThread mWifiServiceHandlerThread;
public WifiStateMachineTest() throws Exception {
}
@@ -401,8 +404,9 @@
when(mWifiInjector.makeWifiConnectivityManager(any(WifiInfo.class), anyBoolean()))
.thenReturn(mWifiConnectivityManager);
when(mWifiInjector.makeSoftApManager(any(INetworkManagementService.class),
- mSoftApManagerListenerCaptor.capture(), any(IApInterface.class),
- any(WifiConfiguration.class)))
+ mSoftApManagerListenerCaptor.capture(),
+ any(IApInterface.class), anyString(),
+ any(SoftApModeConfiguration.class)))
.thenReturn(mSoftApManager);
when(mWifiInjector.getPasspointManager()).thenReturn(mPasspointManager);
when(mWifiInjector.getWifiStateTracker()).thenReturn(mWifiStateTracker);
@@ -412,17 +416,21 @@
when(mWifiInjector.getWifiPermissionsUtil()).thenReturn(mWifiPermissionsUtil);
when(mWifiInjector.makeTelephonyManager()).thenReturn(mTelephonyManager);
when(mWifiInjector.getClock()).thenReturn(mClock);
+ when(mWifiServiceHandlerThread.getLooper()).thenReturn(mLooper.getLooper());
+ when(mWifiInjector.getWifiServiceHandlerThread()).thenReturn(mWifiServiceHandlerThread);
- when(mWifiNative.setupForClientMode())
+ when(mWifiNative.setupForClientMode(WIFI_IFACE_NAME))
.thenReturn(Pair.create(WifiNative.SETUP_SUCCESS, mClientInterface));
- when(mWifiNative.setupForSoftApMode())
+ when(mWifiNative.setupForSoftApMode(WIFI_IFACE_NAME))
.thenReturn(Pair.create(WifiNative.SETUP_SUCCESS, mApInterface));
when(mApInterface.getInterfaceName()).thenReturn(WIFI_IFACE_NAME);
when(mWifiNative.getInterfaceName()).thenReturn(WIFI_IFACE_NAME);
when(mWifiNative.enableSupplicant()).thenReturn(true);
when(mWifiNative.disableSupplicant()).thenReturn(true);
when(mWifiNative.getFrameworkNetworkId(anyInt())).thenReturn(0);
-
+ when(mWifiNative.initializeVendorHal(any(WifiNative.VendorHalDeathEventHandler.class)))
+ .thenReturn(true);
+ when(mWifiNative.registerWificondDeathHandler(any())).thenReturn(true);
mFrameworkFacade = getFrameworkFacade();
mContext = getContext();
@@ -448,9 +456,6 @@
new UserInfo(UserHandle.USER_SYSTEM, "owner", 0),
new UserInfo(11, "managed profile", 0)));
- when(mApInterface.asBinder()).thenReturn(mApInterfaceBinder);
- when(mClientInterface.asBinder()).thenReturn(mClientInterfaceBinder);
-
doAnswer(new AnswerWithArguments() {
public void answer(PhoneStateListener phoneStateListener, int events)
throws Exception {
@@ -460,6 +465,8 @@
when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(true);
initializeWsm();
+
+ mOsuProvider = PasspointProvisioningTestUtil.generateOsuProvider(true);
}
private void registerAsyncChannel(Consumer<AsyncChannel> consumer, Messenger messenger) {
@@ -585,33 +592,36 @@
assertEquals("SoftApState", getCurrentState().getName());
- verify(mWifiNative).setupForSoftApMode();
+ verify(mWifiNative).setupForSoftApMode(WIFI_IFACE_NAME);
verify(mSoftApManager).start();
- // reset expectations for mContext due to previously sent AP broadcast
- reset(mContext);
-
// get the SoftApManager.Listener and trigger some updates
SoftApManager.Listener listener = mSoftApManagerListenerCaptor.getValue();
listener.onStateChanged(WIFI_AP_STATE_ENABLING, 0);
+ assertEquals(WIFI_AP_STATE_ENABLING, mWsm.syncGetWifiApState());
listener.onStateChanged(WIFI_AP_STATE_ENABLED, 0);
+ assertEquals(WIFI_AP_STATE_ENABLED, mWsm.syncGetWifiApState());
listener.onStateChanged(WIFI_AP_STATE_DISABLING, 0);
+ assertEquals(WIFI_AP_STATE_DISABLING, mWsm.syncGetWifiApState());
// note, this will trigger a mode change when TestLooper is dispatched
listener.onStateChanged(WIFI_AP_STATE_DISABLED, 0);
+ assertEquals(WIFI_AP_STATE_DISABLED, mWsm.syncGetWifiApState());
+ }
- ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
- verify(mContext, times(4))
- .sendStickyBroadcastAsUser(intentCaptor.capture(), eq(UserHandle.ALL));
+ private void setupMockWpsPbc() throws Exception {
+ loadComponentsInStaMode();
+ mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
+ mLooper.dispatchAll();
+ assertEquals("DisconnectedState", getCurrentState().getName());
- List<Intent> capturedIntents = intentCaptor.getAllValues();
- checkApStateChangedBroadcast(capturedIntents.get(0), WIFI_AP_STATE_ENABLING,
- WIFI_AP_STATE_DISABLED, HOTSPOT_NO_ERROR, WIFI_IFACE_NAME, mode);
- checkApStateChangedBroadcast(capturedIntents.get(1), WIFI_AP_STATE_ENABLED,
- WIFI_AP_STATE_ENABLING, HOTSPOT_NO_ERROR, WIFI_IFACE_NAME, mode);
- checkApStateChangedBroadcast(capturedIntents.get(2), WIFI_AP_STATE_DISABLING,
- WIFI_AP_STATE_ENABLED, HOTSPOT_NO_ERROR, WIFI_IFACE_NAME, mode);
- checkApStateChangedBroadcast(capturedIntents.get(3), WIFI_AP_STATE_DISABLED,
- WIFI_AP_STATE_DISABLING, HOTSPOT_NO_ERROR, WIFI_IFACE_NAME, mode);
+ WpsInfo wpsInfo = new WpsInfo();
+ wpsInfo.setup = WpsInfo.PBC;
+ wpsInfo.BSSID = sBSSID;
+ when(mWifiNative.removeAllNetworks()).thenReturn(true);
+ when(mWifiNative.startWpsPbc(anyString())).thenReturn(true);
+ mWsm.sendMessage(WifiManager.START_WPS, 0, 0, wpsInfo);
+ mLooper.dispatchAll();
+ assertEquals("WpsRunningState", getCurrentState().getName());
}
@Test
@@ -640,14 +650,13 @@
// We start out with valid default values, break them going backwards so that
// we test all the bailout cases.
- // ClientInterface dies after creation.
- doThrow(new RemoteException()).when(mClientInterfaceBinder).linkToDeath(any(), anyInt());
+ // wificond dies after inteface creation.
+ when(mWifiNative.registerWificondDeathHandler(any())).thenReturn(false);
mWsm.setSupplicantRunning(true);
mLooper.dispatchAll();
assertEquals("InitialState", getCurrentState().getName());
// Failed to even create the client interface.
- when(mWificond.createClientInterface()).thenReturn(null);
mWsm.setSupplicantRunning(true);
mLooper.dispatchAll();
assertEquals("InitialState", getCurrentState().getName());
@@ -960,7 +969,7 @@
mWsm.sendMessage(WifiMonitor.SUP_CONNECTION_EVENT);
mLooper.dispatchAll();
- verify(mWifiNative).setupForClientMode();
+ verify(mWifiNative).setupForClientMode(WIFI_IFACE_NAME);
verify(mWifiLastResortWatchdog).clearAllFailureCounts();
}
@@ -1087,7 +1096,7 @@
private void setupAndStartConnectSequence(WifiConfiguration config) throws Exception {
when(mWifiConfigManager.enableNetwork(eq(config.networkId), eq(true), anyInt()))
.thenReturn(true);
- when(mWifiConfigManager.checkAndUpdateLastConnectUid(eq(config.networkId), anyInt()))
+ when(mWifiConfigManager.updateLastConnectUid(eq(config.networkId), anyInt()))
.thenReturn(true);
when(mWifiConfigManager.getConfiguredNetwork(eq(config.networkId)))
.thenReturn(config);
@@ -1243,44 +1252,6 @@
}
@Test
- public void connectWithNoEnablePermission() throws Exception {
- initializeAndAddNetworkAndVerifySuccess();
- when(mWifiConfigManager.enableNetwork(eq(0), eq(true), anyInt())).thenReturn(false);
- when(mWifiConfigManager.checkAndUpdateLastConnectUid(eq(0), anyInt())).thenReturn(false);
-
- mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
- mLooper.dispatchAll();
- verify(mWifiNative).removeAllNetworks();
-
- mLooper.startAutoDispatch();
- assertTrue(mWsm.syncEnableNetwork(mWsmAsyncChannel, 0, true));
- mLooper.stopAutoDispatch();
-
- verify(mWifiConfigManager).enableNetwork(eq(0), eq(true), anyInt());
- verify(mWifiConnectivityManager, never()).setUserConnectChoice(eq(0));
-
- mWsm.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, 0, 0, sBSSID);
- mLooper.dispatchAll();
-
- mWsm.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
- new StateChangeResult(0, sWifiSsid, sBSSID, SupplicantState.COMPLETED));
- mLooper.dispatchAll();
-
- assertEquals("ObtainingIpState", getCurrentState().getName());
-
- DhcpResults dhcpResults = new DhcpResults();
- dhcpResults.setGateway("1.2.3.4");
- dhcpResults.setIpAddress("192.168.1.100", 0);
- dhcpResults.addDns("8.8.8.8");
- dhcpResults.setLeaseDuration(3600);
-
- injectDhcpSuccess(dhcpResults);
- mLooper.dispatchAll();
-
- assertEquals("ConnectedState", getCurrentState().getName());
- }
-
- @Test
public void enableWithInvalidNetworkId() throws Exception {
initializeAndAddNetworkAndVerifySuccess();
when(mWifiConfigManager.getConfiguredNetwork(eq(0))).thenReturn(null);
@@ -1294,7 +1265,7 @@
mLooper.stopAutoDispatch();
verify(mWifiConfigManager, never()).enableNetwork(eq(0), eq(true), anyInt());
- verify(mWifiConfigManager, never()).checkAndUpdateLastConnectUid(eq(0), anyInt());
+ verify(mWifiConfigManager, never()).updateLastConnectUid(eq(0), anyInt());
}
/**
@@ -1814,6 +1785,57 @@
}
/**
+ * Verify that syncStartSubscriptionProvisioning will redirect calls with right parameters
+ * to {@link PasspointManager} with expected true being returned when in client mode.
+ */
+ @Test
+ public void syncStartSubscriptionProvisioningInClientMode() throws Exception {
+ mLooper.startAutoDispatch();
+ mWsm.syncInitialize(mWsmAsyncChannel);
+ verify(mPasspointManager).initializeProvisioner(any(Looper.class));
+ mLooper.stopAutoDispatch();
+
+ loadComponentsInStaMode();
+ when(mPasspointManager.startSubscriptionProvisioning(anyInt(),
+ any(OsuProvider.class), any(IProvisioningCallback.class))).thenReturn(true);
+ mLooper.startAutoDispatch();
+ assertEquals(true, mWsm.syncStartSubscriptionProvisioning(
+ OTHER_USER_UID, mOsuProvider, mProvisioningCallback, mWsmAsyncChannel));
+ verify(mPasspointManager).startSubscriptionProvisioning(OTHER_USER_UID, mOsuProvider,
+ mProvisioningCallback);
+ mLooper.stopAutoDispatch();
+ }
+
+ /**
+ * Verify that syncStartSubscriptionProvisioning will be a no-op and return false before
+ * SUPPLICANT_START command is received by the WSM.
+ */
+ @Test
+ public void syncStartSubscriptionProvisioningBeforeSupplicantOrAPStart() throws Exception {
+ mLooper.startAutoDispatch();
+ assertEquals(false, mWsm.syncStartSubscriptionProvisioning(
+ OTHER_USER_UID, mOsuProvider, mProvisioningCallback, mWsmAsyncChannel));
+ mLooper.stopAutoDispatch();
+ verify(mPasspointManager, never()).startSubscriptionProvisioning(
+ anyInt(), any(OsuProvider.class), any(IProvisioningCallback.class));
+ }
+
+ /**
+ * Verify that syncStartSubscriptionProvisioning will be a no-op and return false when not in
+ * client mode.
+ */
+ @Test
+ public void syncStartSubscriptionProvisioningInAPMode() throws Exception {
+ loadComponentsInApMode(WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
+ mLooper.startAutoDispatch();
+ assertEquals(false, mWsm.syncStartSubscriptionProvisioning(
+ OTHER_USER_UID, mOsuProvider, mProvisioningCallback, mWsmAsyncChannel));
+ mLooper.stopAutoDispatch();
+ verify(mPasspointManager, never()).startSubscriptionProvisioning(
+ anyInt(), any(OsuProvider.class), any(IProvisioningCallback.class));
+ }
+
+ /**
* Test that we disconnect from a network if it was removed while we are in the
* ObtainingIpState.
*/
@@ -1822,7 +1844,7 @@
initializeAndAddNetworkAndVerifySuccess();
when(mWifiConfigManager.enableNetwork(eq(0), eq(true), anyInt())).thenReturn(true);
- when(mWifiConfigManager.checkAndUpdateLastConnectUid(eq(0), anyInt())).thenReturn(true);
+ when(mWifiConfigManager.updateLastConnectUid(eq(0), anyInt())).thenReturn(true);
mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
mLooper.dispatchAll();
@@ -1880,25 +1902,14 @@
*/
@Test
public void wpsPbcConnectSuccess() throws Exception {
- loadComponentsInStaMode();
- mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
- mLooper.dispatchAll();
- assertEquals("DisconnectedState", getCurrentState().getName());
-
- WpsInfo wpsInfo = new WpsInfo();
- wpsInfo.setup = WpsInfo.PBC;
- wpsInfo.BSSID = sBSSID;
- when(mWifiNative.removeAllNetworks()).thenReturn(true);
- when(mWifiNative.startWpsPbc(anyString())).thenReturn(true);
- mWsm.sendMessage(WifiManager.START_WPS, 0, 0, wpsInfo);
- mLooper.dispatchAll();
- assertEquals("WpsRunningState", getCurrentState().getName());
-
+ setupMockWpsPbc();
setupMocksForWpsNetworkMigration();
mWsm.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, 0, 0, null);
mLooper.dispatchAll();
assertEquals("ObtainingIpState", getCurrentState().getName());
verifyMocksForWpsNetworkMigration();
+ verify(mWifiMetrics).incrementWpsAttemptCount();
+ verify(mWifiMetrics).incrementWpsSuccessCount();
}
/**
@@ -1918,7 +1929,9 @@
mWsm.sendMessage(WifiManager.START_WPS, 0, 0, wpsInfo);
mLooper.dispatchAll();
verify(mWifiNative).startWpsPbc(eq(sBSSID));
-
+ verify(mWifiMetrics).incrementWpsAttemptCount();
+ verify(mWifiMetrics, never()).incrementWpsSuccessCount();
+ verify(mWifiMetrics).incrementWpsStartFailureCount();
assertFalse("WpsRunningState".equals(getCurrentState().getName()));
}
@@ -1928,20 +1941,7 @@
*/
@Test
public void wpsPbcConnectFailure_tooManyConfigs() throws Exception {
- loadComponentsInStaMode();
- mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
- mLooper.dispatchAll();
- assertEquals("DisconnectedState", getCurrentState().getName());
-
- WpsInfo wpsInfo = new WpsInfo();
- wpsInfo.setup = WpsInfo.PBC;
- wpsInfo.BSSID = sBSSID;
- when(mWifiNative.removeAllNetworks()).thenReturn(true);
- when(mWifiNative.startWpsPbc(anyString())).thenReturn(true);
- mWsm.sendMessage(WifiManager.START_WPS, 0, 0, wpsInfo);
- mLooper.dispatchAll();
- assertEquals("WpsRunningState", getCurrentState().getName());
-
+ setupMockWpsPbc();
setupMocksForWpsNetworkMigration();
doAnswer(new AnswerWithArguments() {
public boolean answer(Map<String, WifiConfiguration> configs,
@@ -1953,6 +1953,11 @@
}).when(mWifiNative).migrateNetworksFromSupplicant(any(Map.class), any(SparseArray.class));
mWsm.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, 0, 0, null);
mLooper.dispatchAll();
+ verify(mWifiMetrics).incrementWpsAttemptCount();
+ // When there are multiple networks in supplicant, it returns load success
+ // with invalid network id. Wps framework thinks that network connection succeeded
+ // and messages WPS_COMPLETED.
+ verify(mWifiMetrics).incrementWpsSuccessCount();
assertTrue("DisconnectedState".equals(getCurrentState().getName()));
}
@@ -1962,25 +1967,70 @@
*/
@Test
public void wpsPbcConnectFailure_migrateNetworksFailure() throws Exception {
- loadComponentsInStaMode();
- mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
- mLooper.dispatchAll();
- assertEquals("DisconnectedState", getCurrentState().getName());
-
- WpsInfo wpsInfo = new WpsInfo();
- wpsInfo.setup = WpsInfo.PBC;
- wpsInfo.BSSID = sBSSID;
- when(mWifiNative.removeAllNetworks()).thenReturn(true);
- when(mWifiNative.startWpsPbc(anyString())).thenReturn(true);
- mWsm.sendMessage(WifiManager.START_WPS, 0, 0, wpsInfo);
- mLooper.dispatchAll();
- assertEquals("WpsRunningState", getCurrentState().getName());
-
+ setupMockWpsPbc();
setupMocksForWpsNetworkMigration();
when(mWifiNative.migrateNetworksFromSupplicant(any(Map.class), any(SparseArray.class)))
.thenReturn(false);
mWsm.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, 0, 0, null);
mLooper.dispatchAll();
+ verify(mWifiMetrics, never()).incrementWpsSuccessCount();
+ verify(mWifiMetrics).incrementWpsSupplicantFailureCount();
+ assertEquals("DisconnectedState", getCurrentState().getName());
+ }
+
+ /**
+ * Verify failure in wps overlap event
+ */
+ @Test
+ public void wpsPbcConnectFailure_overlapFailure() throws Exception {
+ setupMockWpsPbc();
+ setupMocksForWpsNetworkMigration();
+ mWsm.sendMessage(WifiMonitor.WPS_OVERLAP_EVENT, 0, 0, null);
+ mLooper.dispatchAll();
+ verify(mWifiMetrics, never()).incrementWpsSuccessCount();
+ verify(mWifiMetrics).incrementWpsOverlapFailureCount();
+ assertEquals("DisconnectedState", getCurrentState().getName());
+ }
+
+ /**
+ * Verify failure in wps timeout event
+ */
+ @Test
+ public void wpsPbcConnectFailure_timeoutFailure() throws Exception {
+ setupMockWpsPbc();
+ setupMocksForWpsNetworkMigration();
+ mWsm.sendMessage(WifiMonitor.WPS_TIMEOUT_EVENT, 0, 0, null);
+ mLooper.dispatchAll();
+ verify(mWifiMetrics, never()).incrementWpsSuccessCount();
+ verify(mWifiMetrics).incrementWpsTimeoutFailureCount();
+ assertEquals("DisconnectedState", getCurrentState().getName());
+ }
+
+ /**
+ * Verify that wps metrics handles WPS_FAIL_EVENT
+ */
+ @Test
+ public void wpsPbcConnectFailure_otherFailure() throws Exception {
+ setupMockWpsPbc();
+ setupMocksForWpsNetworkMigration();
+ mWsm.sendMessage(WifiMonitor.WPS_FAIL_EVENT, 0, 1, null);
+ mLooper.dispatchAll();
+ verify(mWifiMetrics, never()).incrementWpsSuccessCount();
+ verify(mWifiMetrics).incrementWpsOtherConnectionFailureCount();
+ assertEquals("DisconnectedState", getCurrentState().getName());
+ }
+
+ /**
+ * Verify that wps metrics handles connection cancellation
+ */
+ @Test
+ public void wpsPbcConnectCancellation() throws Exception {
+ setupMockWpsPbc();
+ setupMocksForWpsNetworkMigration();
+ mWsm.sendMessage(WifiManager.CANCEL_WPS, 0, 0, null);
+ mLooper.dispatchAll();
+ verify(mWifiMetrics, never()).incrementWpsSuccessCount();
+ verify(mWifiMetrics).incrementWpsCancellationCount();
assertEquals("DisconnectedState", getCurrentState().getName());
}
@@ -2009,6 +2059,7 @@
mWsm.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, 0, 0, null);
mLooper.dispatchAll();
+ verify(mWifiMetrics).incrementWpsSuccessCount();
assertEquals("ObtainingIpState", getCurrentState().getName());
verifyMocksForWpsNetworkMigration();
}
@@ -2030,6 +2081,8 @@
mWsm.sendMessage(WifiManager.START_WPS, 0, 0, wpsInfo);
mLooper.dispatchAll();
verify(mWifiNative).startWpsPinDisplay(eq(sBSSID));
+ verify(mWifiMetrics).incrementWpsAttemptCount();
+ verify(mWifiMetrics).incrementWpsStartFailureCount();
assertFalse("WpsRunningState".equals(getCurrentState().getName()));
}
@@ -2062,20 +2115,19 @@
@Test
public void handleWificondDeath() throws Exception {
- ArgumentCaptor<StateMachineDeathRecipient> deathHandlerCapturer =
- ArgumentCaptor.forClass(StateMachineDeathRecipient.class);
+ ArgumentCaptor<WifiNative.WificondDeathEventHandler> deathHandlerCapturer =
+ ArgumentCaptor.forClass(WifiNative.WificondDeathEventHandler.class);
// Trigger initialize to capture the death handler registration.
loadComponentsInStaMode();
- verify(mClientInterfaceBinder).linkToDeath(deathHandlerCapturer.capture(), anyInt());
- StateMachineDeathRecipient deathHandler = deathHandlerCapturer.getValue();
+ verify(mWifiNative).registerWificondDeathHandler(deathHandlerCapturer.capture());
mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
mLooper.dispatchAll();
// Now trigger the death notification.
- deathHandler.binderDied();
+ deathHandlerCapturer.getValue().onDeath();
mLooper.dispatchAll();
verify(mWifiMetrics).incrementNumWificondCrashes();
@@ -2275,8 +2327,8 @@
assertEquals(sBSSID, wifiInfo.getBSSID());
assertEquals(sWifiSsid, wifiInfo.getWifiSsid());
- when(mWifiPermissionsUtil.canAccessFullConnectionInfo(any(), anyString(), eq(fakeUid),
- anyInt())).thenReturn(false);
+ when(mWifiPermissionsUtil.canAccessScanResults(anyString(), eq(fakeUid), anyInt()))
+ .thenReturn(false);
WifiInfo connectionInfo = mWsm.syncRequestConnectionInfo(mContext.getOpPackageName());
@@ -2308,8 +2360,8 @@
assertEquals(sBSSID, wifiInfo.getBSSID());
assertEquals(sWifiSsid, wifiInfo.getWifiSsid());
- when(mWifiPermissionsUtil.canAccessFullConnectionInfo(any(), anyString(), eq(fakeUid),
- anyInt())).thenThrow(new SecurityException());
+ when(mWifiPermissionsUtil.canAccessScanResults(anyString(), eq(fakeUid), anyInt()))
+ .thenThrow(new SecurityException());
WifiInfo connectionInfo = mWsm.syncRequestConnectionInfo(mContext.getOpPackageName());
@@ -2338,8 +2390,8 @@
assertEquals(sBSSID, wifiInfo.getBSSID());
assertEquals(sWifiSsid, wifiInfo.getWifiSsid());
- when(mWifiPermissionsUtil.canAccessFullConnectionInfo(any(), anyString(), eq(fakeUid),
- anyInt())).thenReturn(true);
+ when(mWifiPermissionsUtil.canAccessScanResults(anyString(), eq(fakeUid), anyInt()))
+ .thenReturn(true);
WifiInfo connectionInfo = mWsm.syncRequestConnectionInfo(mContext.getOpPackageName());
@@ -2404,6 +2456,8 @@
Message reply = mWsmAsyncChannel.sendMessageSynchronously(WifiManager.START_WPS, 0, 0,
null);
mLooper.stopAutoDispatch();
+ verify(mWifiMetrics).incrementWpsAttemptCount();
+ verify(mWifiMetrics).incrementWpsStartFailureCount();
assertEquals(WifiManager.WPS_FAILED, reply.what);
}
@@ -2427,7 +2481,7 @@
*/
@Test
public void testSetupForSoftApModeHalFailureIncrementsMetrics() throws Exception {
- when(mWifiNative.setupForSoftApMode())
+ when(mWifiNative.setupForSoftApMode(WIFI_IFACE_NAME))
.thenReturn(Pair.create(WifiNative.SETUP_FAILURE_HAL, null));
SoftApModeConfiguration config = new SoftApModeConfiguration(
@@ -2435,7 +2489,7 @@
mWsm.setHostApRunning(config, true);
mLooper.dispatchAll();
- verify(mWifiNative).setupForSoftApMode();
+ verify(mWifiNative).setupForSoftApMode(WIFI_IFACE_NAME);
verify(mWifiMetrics).incrementNumWifiOnFailureDueToHal();
}
@@ -2444,7 +2498,7 @@
*/
@Test
public void testSetupForSoftApModeWificondFailureIncrementsMetrics() throws Exception {
- when(mWifiNative.setupForSoftApMode())
+ when(mWifiNative.setupForSoftApMode(WIFI_IFACE_NAME))
.thenReturn(Pair.create(WifiNative.SETUP_FAILURE_WIFICOND, null));
SoftApModeConfiguration config = new SoftApModeConfiguration(
@@ -2452,7 +2506,7 @@
mWsm.setHostApRunning(config, true);
mLooper.dispatchAll();
- verify(mWifiNative).setupForSoftApMode();
+ verify(mWifiNative).setupForSoftApMode(WIFI_IFACE_NAME);
verify(mWifiMetrics).incrementNumWifiOnFailureDueToWificond();
}
@@ -2461,7 +2515,7 @@
*/
@Test
public void testSetupForClientModeHalFailureIncrementsMetrics() throws Exception {
- when(mWifiNative.setupForClientMode())
+ when(mWifiNative.setupForClientMode(WIFI_IFACE_NAME))
.thenReturn(Pair.create(WifiNative.SETUP_FAILURE_HAL, null));
mWsm.setSupplicantRunning(true);
@@ -2470,7 +2524,7 @@
mWsm.sendMessage(WifiMonitor.SUP_CONNECTION_EVENT);
mLooper.dispatchAll();
- verify(mWifiNative).setupForClientMode();
+ verify(mWifiNative).setupForClientMode(WIFI_IFACE_NAME);
verify(mWifiMetrics).incrementNumWifiOnFailureDueToHal();
}
@@ -2479,7 +2533,7 @@
*/
@Test
public void testSetupForClientModeWificondFailureIncrementsMetrics() throws Exception {
- when(mWifiNative.setupForClientMode())
+ when(mWifiNative.setupForClientMode(WIFI_IFACE_NAME))
.thenReturn(Pair.create(WifiNative.SETUP_FAILURE_WIFICOND, null));
mWsm.setSupplicantRunning(true);
@@ -2488,7 +2542,7 @@
mWsm.sendMessage(WifiMonitor.SUP_CONNECTION_EVENT);
mLooper.dispatchAll();
- verify(mWifiNative).setupForClientMode();
+ verify(mWifiNative).setupForClientMode(WIFI_IFACE_NAME);
verify(mWifiMetrics).incrementNumWifiOnFailureDueToWificond();
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiVendorHalTest.java b/tests/wifitests/src/com/android/server/wifi/WifiVendorHalTest.java
index 84de9d2..af8bda4 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiVendorHalTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiVendorHalTest.java
@@ -15,6 +15,30 @@
*/
package com.android.server.wifi;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyObject;
+import static org.mockito.Mockito.anyShort;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
import android.app.test.MockAnswerUtil.AnswerWithArguments;
import android.hardware.wifi.V1_0.IWifiApIface;
import android.hardware.wifi.V1_0.IWifiChip;
@@ -25,8 +49,10 @@
import android.hardware.wifi.V1_0.IWifiStaIface;
import android.hardware.wifi.V1_0.IWifiStaIfaceEventCallback;
import android.hardware.wifi.V1_0.IfaceType;
+import android.hardware.wifi.V1_0.RttBw;
import android.hardware.wifi.V1_0.RttCapabilities;
import android.hardware.wifi.V1_0.RttConfig;
+import android.hardware.wifi.V1_0.RttPreamble;
import android.hardware.wifi.V1_0.StaApfPacketFilterCapabilities;
import android.hardware.wifi.V1_0.StaBackgroundScanCapabilities;
import android.hardware.wifi.V1_0.StaBackgroundScanParameters;
@@ -56,6 +82,7 @@
import android.net.wifi.WifiScanner;
import android.net.wifi.WifiSsid;
import android.net.wifi.WifiWakeReasonAndCounts;
+import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
import android.os.test.TestLooper;
@@ -64,9 +91,6 @@
import com.android.server.connectivity.KeepalivePacketData;
import com.android.server.wifi.util.NativeUtil;
-import static org.junit.Assert.*;
-import static org.mockito.Mockito.*;
-
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
@@ -87,6 +111,7 @@
*/
public class WifiVendorHalTest {
+ private static final String TEST_IFACE_NAME = "wlan0";
WifiVendorHal mWifiVendorHal;
private WifiStatus mWifiStatusSuccess;
private WifiStatus mWifiStatusFailure;
@@ -171,10 +196,10 @@
.thenReturn(mIWifiStaIface);
when(mHalDeviceManager.createApIface(eq(null), eq(null)))
.thenReturn(mIWifiApIface);
+ when(mHalDeviceManager.removeIface(any())).thenReturn(true);
when(mHalDeviceManager.getChip(any(IWifiIface.class)))
.thenReturn(mIWifiChip);
- when(mHalDeviceManager.createRttController(any(IWifiIface.class)))
- .thenReturn(mIWifiRttController);
+ when(mHalDeviceManager.createRttController()).thenReturn(mIWifiRttController);
when(mIWifiChip.registerEventCallback(any(IWifiChipEventCallback.class)))
.thenReturn(mWifiStatusSuccess);
mIWifiStaIfaceEventCallback = null;
@@ -195,6 +220,19 @@
when(mIWifiRttController.registerEventCallback(any(IWifiRttControllerEventCallback.class)))
.thenReturn(mWifiStatusSuccess);
+ doAnswer(new AnswerWithArguments() {
+ public void answer(IWifiIface.getNameCallback cb)
+ throws RemoteException {
+ cb.onValues(mWifiStatusSuccess, TEST_IFACE_NAME);
+ }
+ }).when(mIWifiStaIface).getName(any(IWifiIface.getNameCallback.class));
+ doAnswer(new AnswerWithArguments() {
+ public void answer(IWifiIface.getNameCallback cb)
+ throws RemoteException {
+ cb.onValues(mWifiStatusSuccess, TEST_IFACE_NAME);
+ }
+ }).when(mIWifiApIface).getName(any(IWifiIface.getNameCallback.class));
+
// Create the vendor HAL object under test.
mWifiVendorHal = new WifiVendorHal(mHalDeviceManager, mLooper.getLooper());
@@ -202,24 +240,25 @@
mWifiVendorHal.initialize(mVendorHalDeathHandler);
ArgumentCaptor<WifiVendorHal.HalDeviceManagerStatusListener> hdmCallbackCaptor =
ArgumentCaptor.forClass(WifiVendorHal.HalDeviceManagerStatusListener.class);
- verify(mHalDeviceManager).registerStatusListener(hdmCallbackCaptor.capture(), any());
+ verify(mHalDeviceManager).registerStatusListener(hdmCallbackCaptor.capture(),
+ any(Handler.class));
mHalDeviceManagerStatusCallbacks = hdmCallbackCaptor.getValue();
}
/**
* Tests the successful starting of HAL in STA mode using
- * {@link WifiVendorHal#startVendorHal(boolean)}.
+ * {@link WifiVendorHal#startVendorHalSta()}.
*/
@Test
public void testStartHalSuccessInStaMode() throws Exception {
- assertTrue(mWifiVendorHal.startVendorHal(true));
+ assertTrue(mWifiVendorHal.startVendorHalSta());
assertTrue(mWifiVendorHal.isHalStarted());
verify(mHalDeviceManager).start();
verify(mHalDeviceManager).createStaIface(eq(null), eq(null));
verify(mHalDeviceManager).getChip(eq(mIWifiStaIface));
- verify(mHalDeviceManager).createRttController(eq(mIWifiStaIface));
+ verify(mHalDeviceManager).createRttController();
verify(mHalDeviceManager).isReady();
verify(mHalDeviceManager).isStarted();
verify(mIWifiStaIface).registerEventCallback(any(IWifiStaIfaceEventCallback.class));
@@ -230,11 +269,11 @@
/**
* Tests the successful starting of HAL in AP mode using
- * {@link WifiVendorHal#startVendorHal(boolean)}.
+ * {@link WifiVendorHal#startVendorHalAp()}.
*/
@Test
public void testStartHalSuccessInApMode() throws Exception {
- assertTrue(mWifiVendorHal.startVendorHal(false));
+ assertTrue(mWifiVendorHal.startVendorHalAp());
assertTrue(mWifiVendorHal.isHalStarted());
verify(mHalDeviceManager).start();
@@ -244,12 +283,12 @@
verify(mHalDeviceManager).isStarted();
verify(mHalDeviceManager, never()).createStaIface(eq(null), eq(null));
- verify(mHalDeviceManager, never()).createRttController(any(IWifiIface.class));
+ verify(mHalDeviceManager, never()).createRttController();
}
/**
* Tests the failure to start HAL in STA mode using
- * {@link WifiVendorHal#startVendorHal(boolean)}.
+ * {@link WifiVendorHal#startVendorHalSta()}.
*/
@Test
public void testStartHalFailureInStaMode() throws Exception {
@@ -260,7 +299,7 @@
return false;
}
}).when(mHalDeviceManager).start();
- assertFalse(mWifiVendorHal.startVendorHal(true));
+ assertFalse(mWifiVendorHal.startVendorHalSta());
assertFalse(mWifiVendorHal.isHalStarted());
verify(mHalDeviceManager).start();
@@ -268,19 +307,19 @@
verify(mHalDeviceManager, never()).createStaIface(eq(null), eq(null));
verify(mHalDeviceManager, never()).createApIface(eq(null), eq(null));
verify(mHalDeviceManager, never()).getChip(any(IWifiIface.class));
- verify(mHalDeviceManager, never()).createRttController(any(IWifiIface.class));
+ verify(mHalDeviceManager, never()).createRttController();
verify(mIWifiStaIface, never())
.registerEventCallback(any(IWifiStaIfaceEventCallback.class));
}
/**
* Tests the failure to start HAL in STA mode using
- * {@link WifiVendorHal#startVendorHal(boolean)}.
+ * {@link WifiVendorHal#startVendorHalSta()}.
*/
@Test
public void testStartHalFailureInIfaceCreationInStaMode() throws Exception {
when(mHalDeviceManager.createStaIface(eq(null), eq(null))).thenReturn(null);
- assertFalse(mWifiVendorHal.startVendorHal(true));
+ assertFalse(mWifiVendorHal.startVendorHalSta());
assertFalse(mWifiVendorHal.isHalStarted());
verify(mHalDeviceManager).start();
@@ -289,24 +328,24 @@
verify(mHalDeviceManager, never()).createApIface(eq(null), eq(null));
verify(mHalDeviceManager, never()).getChip(any(IWifiIface.class));
- verify(mHalDeviceManager, never()).createRttController(any(IWifiIface.class));
+ verify(mHalDeviceManager, never()).createRttController();
verify(mIWifiStaIface, never())
.registerEventCallback(any(IWifiStaIfaceEventCallback.class));
}
/**
* Tests the failure to start HAL in STA mode using
- * {@link WifiVendorHal#startVendorHal(boolean)}.
+ * {@link WifiVendorHal#startVendorHalSta()}.
*/
@Test
public void testStartHalFailureInRttControllerCreationInStaMode() throws Exception {
- when(mHalDeviceManager.createRttController(any(IWifiIface.class))).thenReturn(null);
- assertFalse(mWifiVendorHal.startVendorHal(true));
+ when(mHalDeviceManager.createRttController()).thenReturn(null);
+ assertFalse(mWifiVendorHal.startVendorHalSta());
assertFalse(mWifiVendorHal.isHalStarted());
verify(mHalDeviceManager).start();
verify(mHalDeviceManager).createStaIface(eq(null), eq(null));
- verify(mHalDeviceManager).createRttController(eq(mIWifiStaIface));
+ verify(mHalDeviceManager).createRttController();
verify(mHalDeviceManager).stop();
verify(mIWifiStaIface).registerEventCallback(any(IWifiStaIfaceEventCallback.class));
@@ -316,17 +355,17 @@
/**
* Tests the failure to start HAL in STA mode using
- * {@link WifiVendorHal#startVendorHal(boolean)}.
+ * {@link WifiVendorHal#startVendorHalSta()}.
*/
@Test
public void testStartHalFailureInChipGetInStaMode() throws Exception {
when(mHalDeviceManager.getChip(any(IWifiIface.class))).thenReturn(null);
- assertFalse(mWifiVendorHal.startVendorHal(true));
+ assertFalse(mWifiVendorHal.startVendorHalSta());
assertFalse(mWifiVendorHal.isHalStarted());
verify(mHalDeviceManager).start();
verify(mHalDeviceManager).createStaIface(eq(null), eq(null));
- verify(mHalDeviceManager).createRttController(eq(mIWifiStaIface));
+ verify(mHalDeviceManager).createRttController();
verify(mHalDeviceManager).getChip(any(IWifiIface.class));
verify(mHalDeviceManager).stop();
verify(mIWifiStaIface).registerEventCallback(any(IWifiStaIfaceEventCallback.class));
@@ -336,13 +375,13 @@
/**
* Tests the failure to start HAL in STA mode using
- * {@link WifiVendorHal#startVendorHal(boolean)}.
+ * {@link WifiVendorHal#startVendorHalSta()}.
*/
@Test
public void testStartHalFailureInStaIfaceCallbackRegistration() throws Exception {
when(mIWifiStaIface.registerEventCallback(any(IWifiStaIfaceEventCallback.class)))
.thenReturn(mWifiStatusFailure);
- assertFalse(mWifiVendorHal.startVendorHal(true));
+ assertFalse(mWifiVendorHal.startVendorHalSta());
assertFalse(mWifiVendorHal.isHalStarted());
verify(mHalDeviceManager).start();
@@ -350,25 +389,25 @@
verify(mHalDeviceManager).stop();
verify(mIWifiStaIface).registerEventCallback(any(IWifiStaIfaceEventCallback.class));
- verify(mHalDeviceManager, never()).createRttController(eq(mIWifiStaIface));
+ verify(mHalDeviceManager, never()).createRttController();
verify(mHalDeviceManager, never()).getChip(any(IWifiIface.class));
verify(mHalDeviceManager, never()).createApIface(eq(null), eq(null));
}
/**
* Tests the failure to start HAL in STA mode using
- * {@link WifiVendorHal#startVendorHal(boolean)}.
+ * {@link WifiVendorHal#startVendorHalSta()}.
*/
@Test
public void testStartHalFailureInChipCallbackRegistration() throws Exception {
when(mIWifiChip.registerEventCallback(any(IWifiChipEventCallback.class)))
.thenReturn(mWifiStatusFailure);
- assertFalse(mWifiVendorHal.startVendorHal(true));
+ assertFalse(mWifiVendorHal.startVendorHalSta());
assertFalse(mWifiVendorHal.isHalStarted());
verify(mHalDeviceManager).start();
verify(mHalDeviceManager).createStaIface(eq(null), eq(null));
- verify(mHalDeviceManager).createRttController(eq(mIWifiStaIface));
+ verify(mHalDeviceManager).createRttController();
verify(mHalDeviceManager).getChip(any(IWifiIface.class));
verify(mHalDeviceManager).stop();
verify(mIWifiStaIface).registerEventCallback(any(IWifiStaIfaceEventCallback.class));
@@ -378,13 +417,13 @@
}
/**
- * Tests the failure to start HAL in STA mode using
- * {@link WifiVendorHal#startVendorHal(boolean)}.
+ * Tests the failure to start HAL in AP mode using
+ * {@link WifiVendorHal#startVendorHalAp()}.
*/
@Test
public void testStartHalFailureInApMode() throws Exception {
when(mHalDeviceManager.createApIface(eq(null), eq(null))).thenReturn(null);
- assertFalse(mWifiVendorHal.startVendorHal(false));
+ assertFalse(mWifiVendorHal.startVendorHalAp());
assertFalse(mWifiVendorHal.isHalStarted());
verify(mHalDeviceManager).start();
@@ -393,7 +432,7 @@
verify(mHalDeviceManager, never()).createStaIface(eq(null), eq(null));
verify(mHalDeviceManager, never()).getChip(any(IWifiIface.class));
- verify(mHalDeviceManager, never()).createRttController(any(IWifiIface.class));
+ verify(mHalDeviceManager, never()).createRttController();
}
/**
@@ -402,7 +441,7 @@
*/
@Test
public void testStopHalInStaMode() {
- assertTrue(mWifiVendorHal.startVendorHal(true));
+ assertTrue(mWifiVendorHal.startVendorHalSta());
assertTrue(mWifiVendorHal.isHalStarted());
mWifiVendorHal.stopVendorHal();
@@ -412,7 +451,7 @@
verify(mHalDeviceManager).stop();
verify(mHalDeviceManager).createStaIface(eq(null), eq(null));
verify(mHalDeviceManager).getChip(eq(mIWifiStaIface));
- verify(mHalDeviceManager).createRttController(eq(mIWifiStaIface));
+ verify(mHalDeviceManager).createRttController();
verify(mHalDeviceManager, times(2)).isReady();
verify(mHalDeviceManager, times(2)).isStarted();
@@ -425,7 +464,7 @@
*/
@Test
public void testStopHalInApMode() {
- assertTrue(mWifiVendorHal.startVendorHal(false));
+ assertTrue(mWifiVendorHal.startVendorHalAp());
assertTrue(mWifiVendorHal.isHalStarted());
mWifiVendorHal.stopVendorHal();
@@ -439,7 +478,7 @@
verify(mHalDeviceManager, times(2)).isStarted();
verify(mHalDeviceManager, never()).createStaIface(eq(null), eq(null));
- verify(mHalDeviceManager, never()).createRttController(any(IWifiIface.class));
+ verify(mHalDeviceManager, never()).createRttController();
}
/**
@@ -449,7 +488,7 @@
public void testEnterLogging() {
mWifiVendorHal.mLog = spy(mWifiLog);
mWifiVendorHal.enableVerboseLogging(true);
- mWifiVendorHal.installPacketFilter(new byte[0]);
+ mWifiVendorHal.installPacketFilter(TEST_IFACE_NAME, new byte[0]);
verify(mWifiVendorHal.mLog).trace(eq("% filter length %"));
}
@@ -459,10 +498,10 @@
@Test
public void testEnterSilenceWhenNotEnabled() {
mWifiVendorHal.mLog = spy(mWifiLog);
- mWifiVendorHal.installPacketFilter(new byte[0]);
+ mWifiVendorHal.installPacketFilter(TEST_IFACE_NAME, new byte[0]);
mWifiVendorHal.enableVerboseLogging(true);
mWifiVendorHal.enableVerboseLogging(false);
- mWifiVendorHal.installPacketFilter(new byte[0]);
+ mWifiVendorHal.installPacketFilter(TEST_IFACE_NAME, new byte[0]);
verify(mWifiVendorHal.mLog, never()).trace(eq("% filter length %"));
}
@@ -474,7 +513,8 @@
mWifiLog = spy(mWifiLog);
mWifiVendorHal.mLog = mWifiLog;
mWifiVendorHal.mVerboseLog = mWifiLog;
- assertFalse(mWifiVendorHal.getBgScanCapabilities(new WifiNative.ScanCapabilities()));
+ assertFalse(mWifiVendorHal.getBgScanCapabilities(
+ TEST_IFACE_NAME, new WifiNative.ScanCapabilities()));
verify(mWifiLog).err("% returns %");
}
@@ -503,9 +543,12 @@
WifiNative.ScanCapabilities result = new WifiNative.ScanCapabilities();
- assertFalse(mWifiVendorHal.getBgScanCapabilities(result)); // should fail - not started
- assertTrue(mWifiVendorHal.startVendorHalSta()); // Start the vendor hal
- assertTrue(mWifiVendorHal.getBgScanCapabilities(result)); // should succeed
+ // should fail - not started
+ assertFalse(mWifiVendorHal.getBgScanCapabilities(TEST_IFACE_NAME, result));
+ // Start the vendor hal
+ assertTrue(mWifiVendorHal.startVendorHalSta());
+ // should succeed
+ assertTrue(mWifiVendorHal.getBgScanCapabilities(TEST_IFACE_NAME, result));
assertEquals(12, result.max_scan_cache_size);
assertEquals(34, result.max_scan_buckets);
@@ -513,67 +556,6 @@
assertEquals(78, result.max_scan_reporting_threshold);
}
- private void setupValidFrequenciesForBand(ArrayList<Integer> frequencies) throws Exception {
-
- doAnswer(new AnswerWithArguments() {
- public void answer(int band, IWifiStaIface.getValidFrequenciesForBandCallback cb)
- throws RemoteException {
- cb.onValues(mWifiStatusSuccess, frequencies);
- }
- }).when(mIWifiStaIface).getValidFrequenciesForBand(anyInt(), any(
- IWifiStaIface.getValidFrequenciesForBandCallback.class));
-
- doAnswer(new AnswerWithArguments() {
- public void answer(int band, IWifiApIface.getValidFrequenciesForBandCallback cb)
- throws RemoteException {
- cb.onValues(mWifiStatusSuccess, frequencies);
- }
- }).when(mIWifiApIface).getValidFrequenciesForBand(anyInt(), any(
- IWifiApIface.getValidFrequenciesForBandCallback.class));
-
- }
-
- private int[] intArrayFromArrayList(ArrayList<Integer> in) {
- int[] ans = new int[in.size()];
- int i = 0;
- for (Integer e : in) ans[i++] = e;
- return ans;
- }
-
- /**
- * Test that isGetChannelsForBandSupported works in STA mode
- */
- @Test
- public void testGetChannelsForBandSupportedSta() throws Exception {
- ArrayList<Integer> freq = new ArrayList<>();
- freq.add(2405);
-
- setupValidFrequenciesForBand(freq);
-
- assertFalse(mWifiVendorHal.isGetChannelsForBandSupported());
-
- assertTrue(mWifiVendorHal.startVendorHalSta());
-
- assertTrue(mWifiVendorHal.isGetChannelsForBandSupported());
- }
-
- /**
- * Test that isGetChannelsForBandSupported works in AP mode
- */
- @Test
- public void testGetChannelsForBandSupportedAp() throws Exception {
- ArrayList<Integer> freq = new ArrayList<>();
- freq.add(2405);
-
- setupValidFrequenciesForBand(freq);
-
- assertFalse(mWifiVendorHal.isGetChannelsForBandSupported());
-
- assertTrue(mWifiVendorHal.startVendorHalAp());
-
- assertTrue(mWifiVendorHal.isGetChannelsForBandSupported());
- }
-
/**
* Test translation to WifiManager.WIFI_FEATURE_*
*
@@ -620,7 +602,7 @@
*/
@Test
public void testGetSupportedFeatures() throws Exception {
- assertTrue(mWifiVendorHal.startVendorHal(true));
+ assertTrue(mWifiVendorHal.startVendorHalSta());
int staIfaceHidlCaps = (
IWifiStaIface.StaIfaceCapabilityMask.BACKGROUND_SCAN
@@ -653,7 +635,7 @@
when(mHalDeviceManager.getSupportedIfaceTypes())
.thenReturn(halDeviceManagerSupportedIfaces);
- assertEquals(expectedFeatureSet, mWifiVendorHal.getSupportedFeatureSet());
+ assertEquals(expectedFeatureSet, mWifiVendorHal.getSupportedFeatureSet(TEST_IFACE_NAME));
}
/**
@@ -670,13 +652,13 @@
public void testLinkLayerStatsEnableAfterStartup() throws Exception {
doNothing().when(mIWifiStaIface).getLinkLayerStats(any());
- assertNull(mWifiVendorHal.getWifiLinkLayerStats());
+ assertNull(mWifiVendorHal.getWifiLinkLayerStats(TEST_IFACE_NAME));
assertTrue(mWifiVendorHal.startVendorHalSta());
assertTrue(mWifiVendorHal.isHalStarted());
verify(mHalDeviceManager).start();
- mWifiVendorHal.getWifiLinkLayerStats();
- mWifiVendorHal.getWifiLinkLayerStats();
+ mWifiVendorHal.getWifiLinkLayerStats(TEST_IFACE_NAME);
+ mWifiVendorHal.getWifiLinkLayerStats(TEST_IFACE_NAME);
verify(mIWifiStaIface).enableLinkLayerStatsCollection(false); // mLinkLayerStatsDebug
verify(mIWifiStaIface, times(2)).getLinkLayerStats(any());
}
@@ -695,7 +677,7 @@
assertTrue(mWifiVendorHal.startVendorHalAp());
assertTrue(mWifiVendorHal.isHalStarted());
- assertNull(mWifiVendorHal.getWifiLinkLayerStats());
+ assertNull(mWifiVendorHal.getWifiLinkLayerStats(TEST_IFACE_NAME));
verify(mHalDeviceManager).start();
@@ -899,19 +881,52 @@
0, 64);
}
+ /**
+ * Test translation of framwork RttParams to hal RttConfig
+ */
@Test
public void testGetRttStuff() throws Exception {
RttManager.RttParams params = new RttManager.RttParams();
- //TODO(b/34901744) populate
+ params.bssid = "03:01:04:01:05:09";
+ params.frequency = 2420;
+ params.channelWidth = ScanResult.CHANNEL_WIDTH_40MHZ;
+ params.centerFreq0 = 2440;
+ params.centerFreq1 = 1;
+ params.num_samples = 2;
+ params.num_retries = 3;
+ params.numberBurst = 4;
+ params.interval = 5;
+ params.numSamplesPerBurst = 8;
+ params.numRetriesPerMeasurementFrame = 6;
+ params.numRetriesPerFTMR = 7;
+ params.LCIRequest = false;
+ params.LCRRequest = false;
+ params.burstTimeout = 15;
+ String frameish = params.toString();
+ assertFalse(frameish.contains("=0,")); // make sure all fields are initialized
RttConfig config = WifiVendorHal.halRttConfigFromFrameworkRttParams(params);
- //TODO(b/34901744) check
+ String halish = config.toString();
+ StringBuffer expect = new StringBuffer(200);
+ expect.append("{.addr = [3, 1, 4, 1, 5, 9], .type = ONE_SIDED, .peer = AP, ");
+ expect.append(".channel = {.width = WIDTH_40, .centerFreq = 2420, ");
+ expect.append(".centerFreq0 = 2440, .centerFreq1 = 1}, ");
+ expect.append(".burstPeriod = 5, .numBurst = 4, .numFramesPerBurst = 8, ");
+ expect.append(".numRetriesPerRttFrame = 6, .numRetriesPerFtmr = 7, ");
+ expect.append(".mustRequestLci = false, .mustRequestLcr = false, .burstDuration = 15, ");
+ expect.append(".preamble = HT, .bw = BW_20MHZ}");
+ assertEquals(expect.toString(), halish);
}
+ /**
+ * Test that RTT capabilities are plumbed through
+ */
@Test
public void testGetRttCapabilities() throws Exception {
RttCapabilities capabilities = new RttCapabilities();
- //TODO(b/34901744) populate
-
+ capabilities.lcrSupported = true;
+ capabilities.preambleSupport = RttPreamble.LEGACY | RttPreamble.VHT;
+ capabilities.bwSupport = RttBw.BW_5MHZ | RttBw.BW_20MHZ;
+ capabilities.mcVersion = 43;
doAnswer(new AnswerWithArguments() {
public void answer(IWifiRttController.getCapabilitiesCallback cb)
throws RemoteException {
@@ -925,12 +940,21 @@
assertTrue(mWifiVendorHal.startVendorHalSta());
RttManager.RttCapabilities actual = mWifiVendorHal.getRttCapabilities();
- //TODO(b/34901744) check
-
+ assertTrue(actual.lcrSupported);
+ assertEquals(RttManager.PREAMBLE_LEGACY | RttManager.PREAMBLE_VHT,
+ actual.preambleSupported);
+ assertEquals(RttManager.RTT_BW_5_SUPPORT | RttManager.RTT_BW_20_SUPPORT,
+ actual.bwSupported);
+ assertEquals(43, (int) capabilities.mcVersion);
}
- //TODO(b/34901744) negative RTT test cases as well.
- // e.g. invoke RTT without putting the HAL in the correct mode.
+ /**
+ * Negative test of disableRttResponder
+ */
+ @Test
+ public void testDisableOfUnstartedRtt() throws Exception {
+ assertFalse(mWifiVendorHal.disableRttResponder());
+ }
/**
* Test that setScanningMacOui is hooked up to the HAL correctly
@@ -942,12 +966,15 @@
when(mIWifiStaIface.setScanningMacOui(any())).thenReturn(mWifiStatusSuccess);
- assertFalse(mWifiVendorHal.setScanningMacOui(oui)); // expect fail - STA not started
+ // expect fail - STA not started
+ assertFalse(mWifiVendorHal.setScanningMacOui(TEST_IFACE_NAME, oui));
assertTrue(mWifiVendorHal.startVendorHalSta());
- assertFalse(mWifiVendorHal.setScanningMacOui(null)); // expect fail - null
- assertFalse(mWifiVendorHal.setScanningMacOui(new byte[]{(byte) 1})); // expect fail - len
- assertTrue(mWifiVendorHal.setScanningMacOui(oui));
- assertTrue(mWifiVendorHal.setScanningMacOui(zzz));
+ // expect fail - null
+ assertFalse(mWifiVendorHal.setScanningMacOui(TEST_IFACE_NAME, null));
+ // expect fail - len
+ assertFalse(mWifiVendorHal.setScanningMacOui(TEST_IFACE_NAME, new byte[]{(byte) 1}));
+ assertTrue(mWifiVendorHal.setScanningMacOui(TEST_IFACE_NAME, oui));
+ assertTrue(mWifiVendorHal.setScanningMacOui(TEST_IFACE_NAME, zzz));
verify(mIWifiStaIface).setScanningMacOui(eq(oui));
verify(mIWifiStaIface).setScanningMacOui(eq(zzz));
@@ -968,7 +995,8 @@
)).thenReturn(mWifiStatusSuccess);
assertTrue(mWifiVendorHal.startVendorHalSta());
- assertTrue(0 == mWifiVendorHal.startSendingOffloadedPacket(slot, srcMac, kap, millis));
+ assertTrue(0 == mWifiVendorHal.startSendingOffloadedPacket(
+ TEST_IFACE_NAME, slot, srcMac, kap, millis));
verify(mIWifiStaIface).startSendingKeepAlivePackets(
eq(slot), any(), anyShort(), any(), any(), eq(millis));
@@ -981,7 +1009,8 @@
when(mIWifiStaIface.stopSendingKeepAlivePackets(anyInt())).thenReturn(mWifiStatusSuccess);
assertTrue(mWifiVendorHal.startVendorHalSta());
- assertTrue(0 == mWifiVendorHal.stopSendingOffloadedPacket(slot));
+ assertTrue(0 == mWifiVendorHal.stopSendingOffloadedPacket(
+ TEST_IFACE_NAME, slot));
verify(mIWifiStaIface).stopSendingKeepAlivePackets(eq(slot));
}
@@ -1006,20 +1035,26 @@
handler = ((cur) -> {
breach.add(cur);
});
- assertEquals(-1, mWifiVendorHal.startRssiMonitoring(hi, lo, handler)); // not started
- assertEquals(-1, mWifiVendorHal.stopRssiMonitoring()); // not started
+ // not started
+ assertEquals(-1, mWifiVendorHal.startRssiMonitoring(TEST_IFACE_NAME, hi, lo, handler));
+ // not started
+ assertEquals(-1, mWifiVendorHal.stopRssiMonitoring(TEST_IFACE_NAME));
assertTrue(mWifiVendorHal.startVendorHalSta());
- assertEquals(0, mWifiVendorHal.startRssiMonitoring(hi, lo, handler));
+ assertEquals(0, mWifiVendorHal.startRssiMonitoring(TEST_IFACE_NAME, hi, lo, handler));
int theCmdId = mWifiVendorHal.sRssiMonCmdId;
breach.clear();
mIWifiStaIfaceEventCallback.onRssiThresholdBreached(theCmdId, new byte[6], lower);
assertEquals(breach.get(0), lower);
- assertEquals(0, mWifiVendorHal.stopRssiMonitoring());
- assertEquals(0, mWifiVendorHal.startRssiMonitoring(hi, lo, handler));
- assertEquals(0, mWifiVendorHal.startRssiMonitoring(med, lo, handler)); // replacing works
- assertEquals(-1, mWifiVendorHal.startRssiMonitoring(hi, lo, null)); // null handler fails
- assertEquals(0, mWifiVendorHal.startRssiMonitoring(hi, lo, handler));
- assertEquals(-1, mWifiVendorHal.startRssiMonitoring(lo, hi, handler)); // empty range
+ assertEquals(0, mWifiVendorHal.stopRssiMonitoring(TEST_IFACE_NAME));
+ assertEquals(0, mWifiVendorHal.startRssiMonitoring(TEST_IFACE_NAME, hi, lo, handler));
+ // replacing works
+ assertEquals(0, mWifiVendorHal.startRssiMonitoring(TEST_IFACE_NAME, med, lo, handler));
+ // null handler fails
+ assertEquals(-1, mWifiVendorHal.startRssiMonitoring(
+ TEST_IFACE_NAME, hi, lo, null));
+ assertEquals(0, mWifiVendorHal.startRssiMonitoring(TEST_IFACE_NAME, hi, lo, handler));
+ // empty range
+ assertEquals(-1, mWifiVendorHal.startRssiMonitoring(TEST_IFACE_NAME, lo, hi, handler));
}
/**
@@ -1047,11 +1082,12 @@
IWifiStaIface.getApfPacketFilterCapabilitiesCallback.class));
- assertEquals(0, mWifiVendorHal.getApfCapabilities().apfVersionSupported);
+ assertEquals(0, mWifiVendorHal.getApfCapabilities(TEST_IFACE_NAME)
+ .apfVersionSupported);
assertTrue(mWifiVendorHal.startVendorHalSta());
- ApfCapabilities actual = mWifiVendorHal.getApfCapabilities();
+ ApfCapabilities actual = mWifiVendorHal.getApfCapabilities(TEST_IFACE_NAME);
assertEquals(myVersion, actual.apfVersionSupported);
assertEquals(myMaxSize, actual.maximumApfProgramSize);
@@ -1073,7 +1109,7 @@
.thenReturn(mWifiStatusSuccess);
assertTrue(mWifiVendorHal.startVendorHalSta());
- assertTrue(mWifiVendorHal.installPacketFilter(filter));
+ assertTrue(mWifiVendorHal.installPacketFilter(TEST_IFACE_NAME, filter));
verify(mIWifiStaIface).installApfPacketFilter(eq(0), eq(expected));
}
@@ -1090,11 +1126,12 @@
assertTrue(mWifiVendorHal.startVendorHalAp());
- assertFalse(mWifiVendorHal.setCountryCodeHal(null));
- assertFalse(mWifiVendorHal.setCountryCodeHal(""));
- assertFalse(mWifiVendorHal.setCountryCodeHal("A"));
- assertTrue(mWifiVendorHal.setCountryCodeHal("CA")); // Only one expected to succeed
- assertFalse(mWifiVendorHal.setCountryCodeHal("ZZZ"));
+ assertFalse(mWifiVendorHal.setCountryCodeHal(TEST_IFACE_NAME, null));
+ assertFalse(mWifiVendorHal.setCountryCodeHal(TEST_IFACE_NAME, ""));
+ assertFalse(mWifiVendorHal.setCountryCodeHal(TEST_IFACE_NAME, "A"));
+ // Only one expected to succeed
+ assertTrue(mWifiVendorHal.setCountryCodeHal(TEST_IFACE_NAME, "CA"));
+ assertFalse(mWifiVendorHal.setCountryCodeHal(TEST_IFACE_NAME, "ZZZ"));
verify(mIWifiApIface).setCountryCode(eq(expected));
}
@@ -1109,7 +1146,7 @@
when(mIWifiApIface.setCountryCode(any()))
.thenThrow(new RemoteException("oops"));
assertTrue(mWifiVendorHal.startVendorHalAp());
- assertFalse(mWifiVendorHal.setCountryCodeHal("CA"));
+ assertFalse(mWifiVendorHal.setCountryCodeHal(TEST_IFACE_NAME, "CA"));
assertFalse(mWifiVendorHal.isHalStarted());
verify(mWifiLog).err(any());
}
@@ -1226,11 +1263,11 @@
public void testStartPktFateMonitoring() throws Exception {
when(mIWifiStaIface.startDebugPacketFateMonitoring()).thenReturn(mWifiStatusSuccess);
- assertFalse(mWifiVendorHal.startPktFateMonitoring());
+ assertFalse(mWifiVendorHal.startPktFateMonitoring(TEST_IFACE_NAME));
verify(mIWifiStaIface, never()).startDebugPacketFateMonitoring();
assertTrue(mWifiVendorHal.startVendorHalSta());
- assertTrue(mWifiVendorHal.startPktFateMonitoring());
+ assertTrue(mWifiVendorHal.startPktFateMonitoring(TEST_IFACE_NAME));
verify(mIWifiStaIface).startDebugPacketFateMonitoring();
}
@@ -1259,13 +1296,13 @@
.getDebugTxPacketFates(any(IWifiStaIface.getDebugTxPacketFatesCallback.class));
WifiNative.TxFateReport[] retrievedFates = new WifiNative.TxFateReport[1];
- assertFalse(mWifiVendorHal.getTxPktFates(retrievedFates));
+ assertFalse(mWifiVendorHal.getTxPktFates(TEST_IFACE_NAME, retrievedFates));
verify(mIWifiStaIface, never())
.getDebugTxPacketFates(any(IWifiStaIface.getDebugTxPacketFatesCallback.class));
assertTrue(mWifiVendorHal.startVendorHalSta());
- assertTrue(mWifiVendorHal.getTxPktFates(retrievedFates));
+ assertTrue(mWifiVendorHal.getTxPktFates(TEST_IFACE_NAME, retrievedFates));
verify(mIWifiStaIface)
.getDebugTxPacketFates(any(IWifiStaIface.getDebugTxPacketFatesCallback.class));
assertEquals(WifiLoggerHal.TX_PKT_FATE_DRV_QUEUED, retrievedFates[0].mFate);
@@ -1302,13 +1339,13 @@
.getDebugTxPacketFates(any(IWifiStaIface.getDebugTxPacketFatesCallback.class));
WifiNative.TxFateReport[] retrievedFates = new WifiNative.TxFateReport[1];
- assertFalse(mWifiVendorHal.getTxPktFates(retrievedFates));
+ assertFalse(mWifiVendorHal.getTxPktFates(TEST_IFACE_NAME, retrievedFates));
verify(mIWifiStaIface, never())
.getDebugTxPacketFates(any(IWifiStaIface.getDebugTxPacketFatesCallback.class));
assertTrue(mWifiVendorHal.startVendorHalSta());
- assertTrue(mWifiVendorHal.getTxPktFates(retrievedFates));
+ assertTrue(mWifiVendorHal.getTxPktFates(TEST_IFACE_NAME, retrievedFates));
verify(mIWifiStaIface)
.getDebugTxPacketFates(any(IWifiStaIface.getDebugTxPacketFatesCallback.class));
assertEquals(WifiLoggerHal.TX_PKT_FATE_FW_DROP_OTHER, retrievedFates[0].mFate);
@@ -1343,13 +1380,13 @@
.getDebugRxPacketFates(any(IWifiStaIface.getDebugRxPacketFatesCallback.class));
WifiNative.RxFateReport[] retrievedFates = new WifiNative.RxFateReport[1];
- assertFalse(mWifiVendorHal.getRxPktFates(retrievedFates));
+ assertFalse(mWifiVendorHal.getRxPktFates(TEST_IFACE_NAME, retrievedFates));
verify(mIWifiStaIface, never())
.getDebugRxPacketFates(any(IWifiStaIface.getDebugRxPacketFatesCallback.class));
assertTrue(mWifiVendorHal.startVendorHalSta());
- assertTrue(mWifiVendorHal.getRxPktFates(retrievedFates));
+ assertTrue(mWifiVendorHal.getRxPktFates(TEST_IFACE_NAME, retrievedFates));
verify(mIWifiStaIface)
.getDebugRxPacketFates(any(IWifiStaIface.getDebugRxPacketFatesCallback.class));
assertEquals(WifiLoggerHal.RX_PKT_FATE_SUCCESS, retrievedFates[0].mFate);
@@ -1386,13 +1423,13 @@
.getDebugRxPacketFates(any(IWifiStaIface.getDebugRxPacketFatesCallback.class));
WifiNative.RxFateReport[] retrievedFates = new WifiNative.RxFateReport[1];
- assertFalse(mWifiVendorHal.getRxPktFates(retrievedFates));
+ assertFalse(mWifiVendorHal.getRxPktFates(TEST_IFACE_NAME, retrievedFates));
verify(mIWifiStaIface, never())
.getDebugRxPacketFates(any(IWifiStaIface.getDebugRxPacketFatesCallback.class));
assertTrue(mWifiVendorHal.startVendorHalSta());
- assertTrue(mWifiVendorHal.getRxPktFates(retrievedFates));
+ assertTrue(mWifiVendorHal.getRxPktFates(TEST_IFACE_NAME, retrievedFates));
verify(mIWifiStaIface)
.getDebugRxPacketFates(any(IWifiStaIface.getDebugRxPacketFatesCallback.class));
assertEquals(WifiLoggerHal.RX_PKT_FATE_FW_DROP_FILTER, retrievedFates[0].mFate);
@@ -1408,7 +1445,7 @@
@Test
public void testGetTxPktFatesEmptyInputArray() throws Exception {
assertTrue(mWifiVendorHal.startVendorHalSta());
- assertFalse(mWifiVendorHal.getTxPktFates(new WifiNative.TxFateReport[0]));
+ assertFalse(mWifiVendorHal.getTxPktFates(TEST_IFACE_NAME, new WifiNative.TxFateReport[0]));
verify(mIWifiStaIface, never())
.getDebugTxPacketFates(any(IWifiStaIface.getDebugTxPacketFatesCallback.class));
}
@@ -1419,7 +1456,7 @@
@Test
public void testGetRxPktFatesEmptyInputArray() throws Exception {
assertTrue(mWifiVendorHal.startVendorHalSta());
- assertFalse(mWifiVendorHal.getRxPktFates(new WifiNative.RxFateReport[0]));
+ assertFalse(mWifiVendorHal.getRxPktFates(TEST_IFACE_NAME, new WifiNative.RxFateReport[0]));
verify(mIWifiStaIface, never())
.getDebugRxPacketFates(any(IWifiStaIface.getDebugRxPacketFatesCallback.class));
}
@@ -1431,14 +1468,14 @@
public void testEnableDisableNdOffload() throws Exception {
when(mIWifiStaIface.enableNdOffload(anyBoolean())).thenReturn(mWifiStatusSuccess);
- assertFalse(mWifiVendorHal.configureNeighborDiscoveryOffload(true));
+ assertFalse(mWifiVendorHal.configureNeighborDiscoveryOffload(TEST_IFACE_NAME, true));
verify(mIWifiStaIface, never()).enableNdOffload(anyBoolean());
assertTrue(mWifiVendorHal.startVendorHalSta());
- assertTrue(mWifiVendorHal.configureNeighborDiscoveryOffload(true));
+ assertTrue(mWifiVendorHal.configureNeighborDiscoveryOffload(TEST_IFACE_NAME, true));
verify(mIWifiStaIface).enableNdOffload(eq(true));
- assertTrue(mWifiVendorHal.configureNeighborDiscoveryOffload(false));
+ assertTrue(mWifiVendorHal.configureNeighborDiscoveryOffload(TEST_IFACE_NAME, false));
verify(mIWifiStaIface).enableNdOffload(eq(false));
}
@@ -1451,7 +1488,7 @@
assertTrue(mWifiVendorHal.startVendorHalSta());
- assertFalse(mWifiVendorHal.configureNeighborDiscoveryOffload(true));
+ assertFalse(mWifiVendorHal.configureNeighborDiscoveryOffload(TEST_IFACE_NAME, true));
verify(mIWifiStaIface).enableNdOffload(eq(true));
}
@@ -1667,8 +1704,8 @@
int cmdId = mWifiVendorHal.mScan.cmdId;
- mWifiVendorHal.stopBgScan();
- mWifiVendorHal.stopBgScan(); // second call should not do anything
+ mWifiVendorHal.stopBgScan(TEST_IFACE_NAME);
+ mWifiVendorHal.stopBgScan(TEST_IFACE_NAME); // second call should not do anything
verify(mIWifiStaIface).stopBackgroundScan(cmdId); // Should be called just once
}
@@ -1685,8 +1722,8 @@
int cmdId = mWifiVendorHal.mScan.cmdId;
- mWifiVendorHal.pauseBgScan();
- mWifiVendorHal.restartBgScan();
+ mWifiVendorHal.pauseBgScan(TEST_IFACE_NAME);
+ mWifiVendorHal.restartBgScan(TEST_IFACE_NAME);
verify(mIWifiStaIface).stopBackgroundScan(cmdId); // Should be called just once
verify(mIWifiStaIface, times(2)).startBackgroundScan(eq(cmdId), any());
}
@@ -1849,7 +1886,7 @@
*/
@Test
public void testSelectTxPowerScenario() throws RemoteException {
- assertTrue(mWifiVendorHal.startVendorHal(true));
+ assertTrue(mWifiVendorHal.startVendorHalSta());
// Should fail because we exposed the 1.0 IWifiChip.
assertFalse(
mWifiVendorHal.selectTxPowerScenario(WifiNative.TX_POWER_SCENARIO_VOICE_CALL));
@@ -1860,7 +1897,7 @@
mWifiVendorHal = new WifiVendorHalSpyV1_1(mHalDeviceManager, mLooper.getLooper());
when(mIWifiChipV11.selectTxPowerScenario(anyInt())).thenReturn(mWifiStatusSuccess);
- assertTrue(mWifiVendorHal.startVendorHal(true));
+ assertTrue(mWifiVendorHal.startVendorHalSta());
assertTrue(
mWifiVendorHal.selectTxPowerScenario(WifiNative.TX_POWER_SCENARIO_VOICE_CALL));
verify(mIWifiChipV11).selectTxPowerScenario(
@@ -1875,7 +1912,7 @@
*/
@Test
public void testResetTxPowerScenario() throws RemoteException {
- assertTrue(mWifiVendorHal.startVendorHal(true));
+ assertTrue(mWifiVendorHal.startVendorHalSta());
// Should fail because we exposed the 1.0 IWifiChip.
assertFalse(mWifiVendorHal.selectTxPowerScenario(WifiNative.TX_POWER_SCENARIO_NORMAL));
verify(mIWifiChipV11, never()).resetTxPowerScenario();
@@ -1885,7 +1922,7 @@
mWifiVendorHal = new WifiVendorHalSpyV1_1(mHalDeviceManager, mLooper.getLooper());
when(mIWifiChipV11.resetTxPowerScenario()).thenReturn(mWifiStatusSuccess);
- assertTrue(mWifiVendorHal.startVendorHal(true));
+ assertTrue(mWifiVendorHal.startVendorHalSta());
assertTrue(mWifiVendorHal.selectTxPowerScenario(WifiNative.TX_POWER_SCENARIO_NORMAL));
verify(mIWifiChipV11).resetTxPowerScenario();
verify(mIWifiChipV11, never()).selectTxPowerScenario(anyInt());
@@ -1901,13 +1938,73 @@
mWifiVendorHal = new WifiVendorHalSpyV1_1(mHalDeviceManager, mLooper.getLooper());
when(mIWifiChipV11.selectTxPowerScenario(anyInt())).thenReturn(mWifiStatusSuccess);
- assertTrue(mWifiVendorHal.startVendorHal(true));
+ assertTrue(mWifiVendorHal.startVendorHalSta());
assertFalse(mWifiVendorHal.selectTxPowerScenario(-6));
verify(mIWifiChipV11, never()).selectTxPowerScenario(anyInt());
verify(mIWifiChipV11, never()).resetTxPowerScenario();
mWifiVendorHal.stopVendorHal();
}
+ /**
+ * Test the STA Iface creation failure due to iface name retrieval failure.
+ */
+ @Test
+ public void testCreateStaIfaceFailureInIfaceName() throws RemoteException {
+ doAnswer(new AnswerWithArguments() {
+ public void answer(IWifiIface.getNameCallback cb)
+ throws RemoteException {
+ cb.onValues(mWifiStatusFailure, "wlan0");
+ }
+ }).when(mIWifiStaIface).getName(any(IWifiIface.getNameCallback.class));
+
+ assertTrue(mWifiVendorHal.startVendorHal());
+ assertNull(mWifiVendorHal.createStaIface(null));
+ verify(mHalDeviceManager).createStaIface(eq(null), eq(null));
+ }
+
+ /**
+ * Test the STA Iface creation failure due to iface name retrieval failure.
+ */
+ @Test
+ public void testCreateApIfaceFailureInIfaceName() throws RemoteException {
+ doAnswer(new AnswerWithArguments() {
+ public void answer(IWifiIface.getNameCallback cb)
+ throws RemoteException {
+ cb.onValues(mWifiStatusFailure, "wlan0");
+ }
+ }).when(mIWifiApIface).getName(any(IWifiIface.getNameCallback.class));
+
+ assertTrue(mWifiVendorHal.startVendorHal());
+ assertNull(mWifiVendorHal.createApIface(null));
+ verify(mHalDeviceManager).createApIface(eq(null), eq(null));
+ }
+
+ /**
+ * Test the creation and removal of STA Iface.
+ */
+ @Test
+ public void testCreateRemoveStaIface() throws RemoteException {
+ assertTrue(mWifiVendorHal.startVendorHal());
+ String ifaceName = mWifiVendorHal.createStaIface(null);
+ verify(mHalDeviceManager).createStaIface(eq(null), eq(null));
+ assertEquals(TEST_IFACE_NAME, ifaceName);
+ assertTrue(mWifiVendorHal.removeStaIface(ifaceName));
+ verify(mHalDeviceManager).removeIface(eq(mIWifiStaIface));
+ }
+
+ /**
+ * Test the creation and removal of Ap Iface.
+ */
+ @Test
+ public void testCreateRemoveApIface() throws RemoteException {
+ assertTrue(mWifiVendorHal.startVendorHal());
+ String ifaceName = mWifiVendorHal.createApIface(null);
+ verify(mHalDeviceManager).createApIface(eq(null), eq(null));
+ assertEquals(TEST_IFACE_NAME, ifaceName);
+ assertTrue(mWifiVendorHal.removeApIface(ifaceName));
+ verify(mHalDeviceManager).removeIface(eq(mIWifiApIface));
+ }
+
private void startBgScan(WifiNative.ScanEventHandler eventHandler) throws Exception {
when(mIWifiStaIface.startBackgroundScan(
anyInt(), any(StaBackgroundScanParameters.class))).thenReturn(mWifiStatusSuccess);
@@ -1918,7 +2015,7 @@
bucketSettings.period_ms = 16000;
bucketSettings.report_events = WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN;
settings.buckets = new WifiNative.BucketSettings[] {bucketSettings};
- assertTrue(mWifiVendorHal.startBgScan(settings, eventHandler));
+ assertTrue(mWifiVendorHal.startBgScan(TEST_IFACE_NAME, settings, eventHandler));
}
// Create a pair of HIDL scan result and its corresponding framework scan result for
diff --git a/tests/wifitests/src/com/android/server/wifi/WificondControlTest.java b/tests/wifitests/src/com/android/server/wifi/WificondControlTest.java
index cca2045..524324a 100644
--- a/tests/wifitests/src/com/android/server/wifi/WificondControlTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WificondControlTest.java
@@ -16,29 +16,29 @@
package com.android.server.wifi;
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import static android.net.wifi.WifiConfiguration.KeyMgmt.NONE;
+import static android.net.wifi.WifiConfiguration.KeyMgmt.WPA_PSK;
+
+import static org.junit.Assert.*;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Matchers.argThat;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyString;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.*;
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.IWifiScannerImpl;
import android.net.wifi.IWificond;
import android.net.wifi.ScanResult;
+import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiEnterpriseConfig;
import android.net.wifi.WifiScanner;
+import android.os.IBinder;
+import android.os.RemoteException;
import android.test.suitebuilder.annotation.SmallTest;
import com.android.server.wifi.util.NativeUtil;
@@ -52,8 +52,11 @@
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatcher;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import java.io.ByteArrayOutputStream;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.HashSet;
@@ -64,14 +67,23 @@
*/
@SmallTest
public class WificondControlTest {
- private WifiInjector mWifiInjector;
- private WifiMonitor mWifiMonitor;
- private WifiMetrics mWifiMetrics;
- private CarrierNetworkConfig mCarrierNetworkConfig;
+ @Mock private WifiInjector mWifiInjector;
+ @Mock private WifiMonitor mWifiMonitor;
+ @Mock private WifiMetrics mWifiMetrics;
+ @Mock private IWificond mWificond;
+ @Mock private IBinder mWifiCondBinder;
+ @Mock private IClientInterface mClientInterface;
+ @Mock private IWifiScannerImpl mWifiScannerImpl;
+ @Mock private CarrierNetworkConfig mCarrierNetworkConfig;
+ @Mock private IApInterface mApInterface;
+ @Mock private WifiNative.SoftApListener mSoftApListener;
private WificondControl mWificondControl;
private static final String TEST_INTERFACE_NAME = "test_wlan_if";
+ private static final String TEST_INTERFACE_NAME1 = "test_wlan_if1";
private static final byte[] TEST_SSID =
new byte[] {'G', 'o', 'o', 'g', 'l', 'e', 'G', 'u', 'e', 's', 't'};
+ private static final byte[] TEST_PSK =
+ new byte[] {'T', 'e', 's', 't'};
private static final byte[] TEST_BSSID =
new byte[] {(byte) 0x12, (byte) 0xef, (byte) 0xa1,
(byte) 0x2c, (byte) 0x97, (byte) 0x8b};
@@ -144,109 +156,241 @@
@Before
public void setUp() throws Exception {
- mWifiInjector = mock(WifiInjector.class);
- mWifiMonitor = mock(WifiMonitor.class);
- mWifiMetrics = mock(WifiMetrics.class);
+ // Setup mocks for successful WificondControl operation. Failure case mocks should be
+ // created in specific tests
+ MockitoAnnotations.initMocks(this);
+ when(mWifiInjector.makeWificond()).thenReturn(mWificond);
+ when(mWificond.asBinder()).thenReturn(mWifiCondBinder);
+ when(mClientInterface.getWifiScannerImpl()).thenReturn(mWifiScannerImpl);
+ when(mWificond.createClientInterface(any())).thenReturn(mClientInterface);
+ when(mWificond.createApInterface(any())).thenReturn(mApInterface);
+ when(mWificond.tearDownClientInterface(any())).thenReturn(true);
+ when(mWificond.tearDownApInterface(any())).thenReturn(true);
+ when(mClientInterface.getWifiScannerImpl()).thenReturn(mWifiScannerImpl);
+ when(mClientInterface.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
when(mWifiInjector.getWifiMetrics()).thenReturn(mWifiMetrics);
- mCarrierNetworkConfig = mock(CarrierNetworkConfig.class);
mWificondControl = new WificondControl(mWifiInjector, mWifiMonitor, mCarrierNetworkConfig);
+ assertEquals(mClientInterface, mWificondControl.setupInterfaceForClientMode(
+ TEST_INTERFACE_NAME));
+ verify(mWifiInjector).makeWificond();
+ verify(mWifiCondBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt());
}
/**
- * Verifies that setupDriverForClientMode() calls Wificond.
+ * Verifies that setupInterfaceForClientMode(TEST_INTERFACE_NAME) calls Wificond.
*/
@Test
- public void testSetupDriverForClientMode() throws Exception {
- IWificond wificond = mock(IWificond.class);
- IClientInterface clientInterface = getMockClientInterface();
-
- when(mWifiInjector.makeWificond()).thenReturn(wificond);
- when(wificond.createClientInterface()).thenReturn(clientInterface);
-
- IClientInterface returnedClientInterface = mWificondControl.setupDriverForClientMode();
- assertEquals(clientInterface, returnedClientInterface);
- verify(wificond).createClientInterface();
+ public void testSetupInterfaceForClientMode() throws Exception {
+ when(mWifiInjector.makeWificond()).thenReturn(mWificond);
+ when(mWificond.createClientInterface(TEST_INTERFACE_NAME)).thenReturn(mClientInterface);
+ verify(mWificond).createClientInterface(TEST_INTERFACE_NAME);
}
/**
- * Verifies that setupDriverForClientMode() calls subscribeScanEvents().
+ * Verifies that setupInterfaceForClientMode(TEST_INTERFACE_NAME) calls subscribeScanEvents().
*/
@Test
- public void testSetupDriverForClientModeCallsScanEventSubscripiton() throws Exception {
- IWifiScannerImpl scanner = setupClientInterfaceAndCreateMockWificondScanner();
-
- verify(scanner).subscribeScanEvents(any(IScanEvent.class));
+ public void testSetupInterfaceForClientModeCallsScanEventSubscripiton() throws Exception {
+ verify(mWifiScannerImpl).subscribeScanEvents(any(IScanEvent.class));
}
/**
- * Verifies that setupDriverForClientMode() returns null when wificond is not started.
+ * Verifies that setupInterfaceForClientMode(TEST_INTERFACE_NAME) returns null when wificond is
+ * not started.
*/
@Test
- public void testSetupDriverForClientModeErrorWhenWificondIsNotStarted() throws Exception {
+ public void testSetupInterfaceForClientModeErrorWhenWificondIsNotStarted() throws Exception {
+ // Invoke wificond death handler to clear the handle.
+ mWificondControl.binderDied();
when(mWifiInjector.makeWificond()).thenReturn(null);
+ IClientInterface returnedClientInterface =
+ mWificondControl.setupInterfaceForClientMode(TEST_INTERFACE_NAME);
+ assertEquals(null, returnedClientInterface);
+ verify(mWifiInjector, times(2)).makeWificond();
+ }
- IClientInterface returnedClientInterface = mWificondControl.setupDriverForClientMode();
+ /**
+ * Verifies that setupInterfaceForClientMode(TEST_INTERFACE_NAME) returns null when wificond
+ * failed to setup client interface.
+ */
+ @Test
+ public void testSetupInterfaceForClientModeErrorWhenWificondFailedToSetupInterface()
+ throws Exception {
+ when(mWifiInjector.makeWificond()).thenReturn(mWificond);
+ when(mWificond.createClientInterface(TEST_INTERFACE_NAME)).thenReturn(null);
+
+ IClientInterface returnedClientInterface =
+ mWificondControl.setupInterfaceForClientMode(TEST_INTERFACE_NAME);
assertEquals(null, returnedClientInterface);
}
/**
- * Verifies that setupDriverForClientMode() returns null when wificond failed to setup client
- * interface.
+ * Verifies that tearDownClientInterface(TEST_INTERFACE_NAME) calls Wificond.
*/
@Test
- public void testSetupDriverForClientModeErrorWhenWificondFailedToSetupInterface()
- throws Exception {
- IWificond wificond = mock(IWificond.class);
+ public void testTeardownClientInterface() throws Exception {
+ when(mWificond.tearDownClientInterface(TEST_INTERFACE_NAME)).thenReturn(true);
- when(mWifiInjector.makeWificond()).thenReturn(wificond);
- when(wificond.createClientInterface()).thenReturn(null);
-
- IClientInterface returnedClientInterface = mWificondControl.setupDriverForClientMode();
- assertEquals(null, returnedClientInterface);
+ assertTrue(mWificondControl.tearDownClientInterface(TEST_INTERFACE_NAME));
+ verify(mWifiScannerImpl).unsubscribeScanEvents();
+ verify(mWifiScannerImpl).unsubscribePnoScanEvents();
+ verify(mWificond).tearDownClientInterface(TEST_INTERFACE_NAME);
}
/**
- * Verifies that setupDriverForSoftApMode() calls wificond.
+ * Verifies that tearDownClientInterface(TEST_INTERFACE_NAME) calls Wificond.
*/
@Test
- public void testSetupDriverForSoftApMode() throws Exception {
- IWificond wificond = mock(IWificond.class);
- IApInterface apInterface = mock(IApInterface.class);
+ public void testTeardownClientInterfaceFailDueToExceptionScannerUnsubscribe() throws Exception {
+ when(mWificond.tearDownClientInterface(TEST_INTERFACE_NAME)).thenReturn(true);
+ doThrow(new RemoteException()).when(mWifiScannerImpl).unsubscribeScanEvents();
- when(mWifiInjector.makeWificond()).thenReturn(wificond);
- when(wificond.createApInterface()).thenReturn(apInterface);
+ assertFalse(mWificondControl.tearDownClientInterface(TEST_INTERFACE_NAME));
+ verify(mWifiScannerImpl).unsubscribeScanEvents();
+ verify(mWifiScannerImpl, never()).unsubscribePnoScanEvents();
+ verify(mWificond, never()).tearDownClientInterface(TEST_INTERFACE_NAME);
+ }
+ /**
+ * Verifies that tearDownClientInterface(TEST_INTERFACE_NAME) calls Wificond.
+ */
+ @Test
+ public void testTeardownClientInterfaceErrorWhenWificondFailed() throws Exception {
+ when(mWificond.tearDownClientInterface(TEST_INTERFACE_NAME)).thenReturn(false);
- IApInterface returnedApInterface = mWificondControl.setupDriverForSoftApMode();
- assertEquals(apInterface, returnedApInterface);
- verify(wificond).createApInterface();
+ assertFalse(mWificondControl.tearDownClientInterface(TEST_INTERFACE_NAME));
+ verify(mWifiScannerImpl).unsubscribeScanEvents();
+ verify(mWifiScannerImpl).unsubscribePnoScanEvents();
+ verify(mWificond).tearDownClientInterface(TEST_INTERFACE_NAME);
}
/**
- * Verifies that setupDriverForSoftAp() returns null when wificond is not started.
+ * Verifies that the client handles are cleared after teardown.
*/
@Test
- public void testSetupDriverForSoftApModeErrorWhenWificondIsNotStarted() throws Exception {
+ public void testTeardownClientInterfaceClearsHandles() throws Exception {
+ testTeardownClientInterface();
+
+ assertNull(mWificondControl.signalPoll(TEST_INTERFACE_NAME));
+ verify(mClientInterface, never()).signalPoll();
+
+ assertFalse(mWificondControl.scan(
+ TEST_INTERFACE_NAME, SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_SET));
+ verify(mWifiScannerImpl, never()).scan(any());
+ }
+
+ /**
+ * Verifies that setupInterfaceForSoftApMode(TEST_INTERFACE_NAME) calls wificond.
+ */
+ @Test
+ public void testSetupInterfaceForSoftApMode() throws Exception {
+ when(mWifiInjector.makeWificond()).thenReturn(mWificond);
+ when(mWificond.createApInterface(TEST_INTERFACE_NAME)).thenReturn(mApInterface);
+
+ IApInterface returnedApInterface =
+ mWificondControl.setupInterfaceForSoftApMode(TEST_INTERFACE_NAME);
+ assertEquals(mApInterface, returnedApInterface);
+ verify(mWifiInjector).makeWificond();
+ verify(mWifiCondBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt());
+ verify(mWificond).createApInterface(TEST_INTERFACE_NAME);
+ }
+
+ /**
+ * Verifies that setupInterfaceForSoftAp() returns null when wificond is not started.
+ */
+ @Test
+ public void testSetupInterfaceForSoftApModeErrorWhenWificondIsNotStarted() throws Exception {
+ // Invoke wificond death handler to clear the handle.
+ mWificondControl.binderDied();
when(mWifiInjector.makeWificond()).thenReturn(null);
- IApInterface returnedApInterface = mWificondControl.setupDriverForSoftApMode();
+ IApInterface returnedApInterface =
+ mWificondControl.setupInterfaceForSoftApMode(TEST_INTERFACE_NAME);
assertEquals(null, returnedApInterface);
+ verify(mWifiInjector, times(2)).makeWificond();
+ }
+
+ /**
+ * Verifies that setupInterfaceForSoftApMode(TEST_INTERFACE_NAME) returns null when wificond
+ * failed to setup AP interface.
+ */
+ @Test
+ public void testSetupInterfaceForSoftApModeErrorWhenWificondFailedToSetupInterface()
+ throws Exception {
+ when(mWifiInjector.makeWificond()).thenReturn(mWificond);
+ when(mWificond.createApInterface(TEST_INTERFACE_NAME)).thenReturn(null);
+
+ IApInterface returnedApInterface =
+ mWificondControl.setupInterfaceForSoftApMode(TEST_INTERFACE_NAME);
+ assertEquals(null, returnedApInterface);
}
/**
- * Verifies that setupDriverForSoftApMode() returns null when wificond failed to setup
- * AP interface.
+ * Verifies that tearDownClientInterface(TEST_INTERFACE_NAME) calls Wificond.
*/
@Test
- public void testSetupDriverForSoftApModeErrorWhenWificondFailedToSetupInterface()
- throws Exception {
- IWificond wificond = mock(IWificond.class);
+ public void testTeardownSoftApInterface() throws Exception {
+ testSetupInterfaceForSoftApMode();
+ when(mWificond.tearDownApInterface(TEST_INTERFACE_NAME)).thenReturn(true);
- when(mWifiInjector.makeWificond()).thenReturn(wificond);
- when(wificond.createApInterface()).thenReturn(null);
+ assertTrue(mWificondControl.tearDownSoftApInterface(TEST_INTERFACE_NAME));
+ verify(mWificond).tearDownApInterface(TEST_INTERFACE_NAME);
+ }
- IApInterface returnedApInterface = mWificondControl.setupDriverForSoftApMode();
- assertEquals(null, returnedApInterface);
+ /**
+ * Verifies that tearDownClientInterface(TEST_INTERFACE_NAME) calls Wificond.
+ */
+ @Test
+ public void testTeardownSoftApInterfaceErrorWhenWificondFailed() throws Exception {
+ testSetupInterfaceForSoftApMode();
+ when(mWificond.tearDownApInterface(TEST_INTERFACE_NAME)).thenReturn(false);
+
+ assertFalse(mWificondControl.tearDownSoftApInterface(TEST_INTERFACE_NAME));
+ verify(mWificond).tearDownApInterface(TEST_INTERFACE_NAME);
+ }
+
+ /**
+ * Verifies that the SoftAp handles are cleared after teardown.
+ */
+ @Test
+ public void testTeardownSoftApInterfaceClearsHandles() throws Exception {
+ testTeardownSoftApInterface();
+
+ assertFalse(mWificondControl.startSoftAp(
+ TEST_INTERFACE_NAME, new WifiConfiguration(), mSoftApListener));
+ verify(mApInterface, never()).writeHostapdConfig(
+ any(byte[].class), anyBoolean(), anyInt(), anyInt(), any(byte[].class));
+ verify(mApInterface, never()).startHostapd(any());
+ }
+
+ /**
+ * Verifies that we can setup concurrent interfaces.
+ */
+ @Test
+ public void testSetupMulitpleInterfaces() throws Exception {
+ when(mWificond.createApInterface(TEST_INTERFACE_NAME1)).thenReturn(mApInterface);
+
+ IApInterface returnedApInterface =
+ mWificondControl.setupInterfaceForSoftApMode(TEST_INTERFACE_NAME1);
+ assertEquals(mApInterface, returnedApInterface);
+ verify(mWifiInjector).makeWificond();
+ verify(mWifiCondBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt());
+
+ verify(mWificond).createClientInterface(TEST_INTERFACE_NAME);
+ verify(mWificond).createApInterface(TEST_INTERFACE_NAME1);
+ }
+
+ /**
+ * Verifies that we can setup concurrent interfaces.
+ */
+ @Test
+ public void testTeardownMulitpleInterfaces() throws Exception {
+ testSetupMulitpleInterfaces();
+ assertTrue(mWificondControl.tearDownClientInterface(TEST_INTERFACE_NAME));
+ assertTrue(mWificondControl.tearDownSoftApInterface(TEST_INTERFACE_NAME1));
+
+ verify(mWificond).tearDownClientInterface(TEST_INTERFACE_NAME);
+ verify(mWificond).tearDownApInterface(TEST_INTERFACE_NAME1);
}
/**
@@ -254,16 +398,12 @@
*/
@Test
public void testEnableSupplicant() throws Exception {
- IWificond wificond = mock(IWificond.class);
- IClientInterface clientInterface = getMockClientInterface();
+ when(mWifiInjector.makeWificond()).thenReturn(mWificond);
+ when(mWificond.enableSupplicant()).thenReturn(true);
- when(mWifiInjector.makeWificond()).thenReturn(wificond);
- when(wificond.createClientInterface()).thenReturn(clientInterface);
- when(clientInterface.enableSupplicant()).thenReturn(true);
-
- mWificondControl.setupDriverForClientMode();
assertTrue(mWificondControl.enableSupplicant());
- verify(clientInterface).enableSupplicant();
+ verify(mWifiInjector).makeWificond();
+ verify(mWificond).enableSupplicant();
}
/**
@@ -272,15 +412,13 @@
*/
@Test
public void testEnableSupplicantErrorWhenNoClientInterfaceConfigured() throws Exception {
- IWificond wificond = mock(IWificond.class);
- IClientInterface clientInterface = getMockClientInterface();
-
- when(mWifiInjector.makeWificond()).thenReturn(wificond);
- when(wificond.createClientInterface()).thenReturn(clientInterface);
+ when(mWifiInjector.makeWificond()).thenReturn(mWificond);
+ when(mWificond.createClientInterface(TEST_INTERFACE_NAME)).thenReturn(mClientInterface);
// Configure client interface.
- IClientInterface returnedClientInterface = mWificondControl.setupDriverForClientMode();
- assertEquals(clientInterface, returnedClientInterface);
+ IClientInterface returnedClientInterface =
+ mWificondControl.setupInterfaceForClientMode(TEST_INTERFACE_NAME);
+ assertEquals(mClientInterface, returnedClientInterface);
// Tear down interfaces.
assertTrue(mWificondControl.tearDownInterfaces());
@@ -294,16 +432,12 @@
*/
@Test
public void testDisableSupplicant() throws Exception {
- IWificond wificond = mock(IWificond.class);
- IClientInterface clientInterface = getMockClientInterface();
+ when(mWifiInjector.makeWificond()).thenReturn(mWificond);
+ when(mWificond.disableSupplicant()).thenReturn(true);
- when(mWifiInjector.makeWificond()).thenReturn(wificond);
- when(wificond.createClientInterface()).thenReturn(clientInterface);
- when(clientInterface.disableSupplicant()).thenReturn(true);
-
- mWificondControl.setupDriverForClientMode();
assertTrue(mWificondControl.disableSupplicant());
- verify(clientInterface).disableSupplicant();
+ verify(mWifiInjector).makeWificond();
+ verify(mWificond).disableSupplicant();
}
/**
@@ -312,15 +446,13 @@
*/
@Test
public void testDisableSupplicantErrorWhenNoClientInterfaceConfigured() throws Exception {
- IWificond wificond = mock(IWificond.class);
- IClientInterface clientInterface = getMockClientInterface();
-
- when(mWifiInjector.makeWificond()).thenReturn(wificond);
- when(wificond.createClientInterface()).thenReturn(clientInterface);
+ when(mWifiInjector.makeWificond()).thenReturn(mWificond);
+ when(mWificond.createClientInterface(TEST_INTERFACE_NAME)).thenReturn(mClientInterface);
// Configure client interface.
- IClientInterface returnedClientInterface = mWificondControl.setupDriverForClientMode();
- assertEquals(clientInterface, returnedClientInterface);
+ IClientInterface returnedClientInterface =
+ mWificondControl.setupInterfaceForClientMode(TEST_INTERFACE_NAME);
+ assertEquals(mClientInterface, returnedClientInterface);
// Tear down interfaces.
assertTrue(mWificondControl.tearDownInterfaces());
@@ -334,12 +466,9 @@
*/
@Test
public void testTearDownInterfaces() throws Exception {
- IWificond wificond = mock(IWificond.class);
-
- when(mWifiInjector.makeWificond()).thenReturn(wificond);
+ when(mWifiInjector.makeWificond()).thenReturn(mWificond);
assertTrue(mWificondControl.tearDownInterfaces());
-
- verify(wificond).tearDownInterfaces();
+ verify(mWificond).tearDownInterfaces();
}
/**
@@ -348,11 +477,8 @@
*/
@Test
public void testTearDownInterfacesRemovesScanEventSubscription() throws Exception {
- IWifiScannerImpl scanner = setupClientInterfaceAndCreateMockWificondScanner();
-
assertTrue(mWificondControl.tearDownInterfaces());
-
- verify(scanner).unsubscribeScanEvents();
+ verify(mWifiScannerImpl).unsubscribeScanEvents();
}
@@ -361,8 +487,9 @@
*/
@Test
public void testTearDownInterfacesErrorWhenWificondIsNotStarterd() throws Exception {
+ // Invoke wificond death handler to clear the handle.
+ mWificondControl.binderDied();
when(mWifiInjector.makeWificond()).thenReturn(null);
-
assertFalse(mWificondControl.tearDownInterfaces());
}
@@ -371,15 +498,12 @@
*/
@Test
public void testSignalPoll() throws Exception {
- IWificond wificond = mock(IWificond.class);
- IClientInterface clientInterface = getMockClientInterface();
+ when(mWifiInjector.makeWificond()).thenReturn(mWificond);
+ when(mWificond.createClientInterface(TEST_INTERFACE_NAME)).thenReturn(mClientInterface);
- when(mWifiInjector.makeWificond()).thenReturn(wificond);
- when(wificond.createClientInterface()).thenReturn(clientInterface);
-
- mWificondControl.setupDriverForClientMode();
- mWificondControl.signalPoll();
- verify(clientInterface).signalPoll();
+ mWificondControl.setupInterfaceForClientMode(TEST_INTERFACE_NAME);
+ mWificondControl.signalPoll(TEST_INTERFACE_NAME);
+ verify(mClientInterface).signalPoll();
}
/**
@@ -387,21 +511,19 @@
*/
@Test
public void testSignalPollErrorWhenNoClientInterfaceConfigured() throws Exception {
- IWificond wificond = mock(IWificond.class);
- IClientInterface clientInterface = getMockClientInterface();
-
- when(mWifiInjector.makeWificond()).thenReturn(wificond);
- when(wificond.createClientInterface()).thenReturn(clientInterface);
+ when(mWifiInjector.makeWificond()).thenReturn(mWificond);
+ when(mWificond.createClientInterface(TEST_INTERFACE_NAME)).thenReturn(mClientInterface);
// Configure client interface.
- IClientInterface returnedClientInterface = mWificondControl.setupDriverForClientMode();
- assertEquals(clientInterface, returnedClientInterface);
+ IClientInterface returnedClientInterface =
+ mWificondControl.setupInterfaceForClientMode(TEST_INTERFACE_NAME);
+ assertEquals(mClientInterface, returnedClientInterface);
// Tear down interfaces.
assertTrue(mWificondControl.tearDownInterfaces());
// Signal poll should fail.
- assertEquals(null, mWificondControl.signalPoll());
+ assertEquals(null, mWificondControl.signalPoll(TEST_INTERFACE_NAME));
}
/**
@@ -409,15 +531,12 @@
*/
@Test
public void testGetTxPacketCounters() throws Exception {
- IWificond wificond = mock(IWificond.class);
- IClientInterface clientInterface = getMockClientInterface();
+ when(mWifiInjector.makeWificond()).thenReturn(mWificond);
+ when(mWificond.createClientInterface(TEST_INTERFACE_NAME)).thenReturn(mClientInterface);
- when(mWifiInjector.makeWificond()).thenReturn(wificond);
- when(wificond.createClientInterface()).thenReturn(clientInterface);
-
- mWificondControl.setupDriverForClientMode();
- mWificondControl.getTxPacketCounters();
- verify(clientInterface).getPacketCounters();
+ mWificondControl.setupInterfaceForClientMode(TEST_INTERFACE_NAME);
+ mWificondControl.getTxPacketCounters(TEST_INTERFACE_NAME);
+ verify(mClientInterface).getPacketCounters();
}
/**
@@ -426,21 +545,19 @@
*/
@Test
public void testGetTxPacketCountersErrorWhenNoClientInterfaceConfigured() throws Exception {
- IWificond wificond = mock(IWificond.class);
- IClientInterface clientInterface = getMockClientInterface();
-
- when(mWifiInjector.makeWificond()).thenReturn(wificond);
- when(wificond.createClientInterface()).thenReturn(clientInterface);
+ when(mWifiInjector.makeWificond()).thenReturn(mWificond);
+ when(mWificond.createClientInterface(TEST_INTERFACE_NAME)).thenReturn(mClientInterface);
// Configure client interface.
- IClientInterface returnedClientInterface = mWificondControl.setupDriverForClientMode();
- assertEquals(clientInterface, returnedClientInterface);
+ IClientInterface returnedClientInterface =
+ mWificondControl.setupInterfaceForClientMode(TEST_INTERFACE_NAME);
+ assertEquals(mClientInterface, returnedClientInterface);
// Tear down interfaces.
assertTrue(mWificondControl.tearDownInterfaces());
// Signal poll should fail.
- assertEquals(null, mWificondControl.getTxPacketCounters());
+ assertEquals(null, mWificondControl.getTxPacketCounters(TEST_INTERFACE_NAME));
}
/**
@@ -449,22 +566,21 @@
*/
@Test
public void testGetScanResultsErrorWhenNoClientInterfaceConfigured() throws Exception {
- IWificond wificond = mock(IWificond.class);
- IClientInterface clientInterface = getMockClientInterface();
-
- when(mWifiInjector.makeWificond()).thenReturn(wificond);
- when(wificond.createClientInterface()).thenReturn(clientInterface);
+ when(mWifiInjector.makeWificond()).thenReturn(mWificond);
+ when(mWificond.createClientInterface(TEST_INTERFACE_NAME)).thenReturn(mClientInterface);
// Configure client interface.
- IClientInterface returnedClientInterface = mWificondControl.setupDriverForClientMode();
- assertEquals(clientInterface, returnedClientInterface);
+ IClientInterface returnedClientInterface =
+ mWificondControl.setupInterfaceForClientMode(TEST_INTERFACE_NAME);
+ assertEquals(mClientInterface, returnedClientInterface);
// Tear down interfaces.
assertTrue(mWificondControl.tearDownInterfaces());
// getScanResults should fail.
assertEquals(0,
- mWificondControl.getScanResults(WificondControl.SCAN_TYPE_SINGLE_SCAN).size());
+ mWificondControl.getScanResults(TEST_INTERFACE_NAME,
+ WificondControl.SCAN_TYPE_SINGLE_SCAN).size());
}
/**
@@ -472,15 +588,14 @@
*/
@Test
public void testGetScanResults() throws Exception {
- IWifiScannerImpl scanner = setupClientInterfaceAndCreateMockWificondScanner();
- assertNotNull(scanner);
+ assertNotNull(mWifiScannerImpl);
// Mock the returned array of NativeScanResult.
NativeScanResult[] mockScanResults = {MOCK_NATIVE_SCAN_RESULT};
- when(scanner.getScanResults()).thenReturn(mockScanResults);
+ when(mWifiScannerImpl.getScanResults()).thenReturn(mockScanResults);
ArrayList<ScanDetail> returnedScanResults = mWificondControl.getScanResults(
- WificondControl.SCAN_TYPE_SINGLE_SCAN);
+ TEST_INTERFACE_NAME, WificondControl.SCAN_TYPE_SINGLE_SCAN);
// The test IEs {@link #TEST_INFO_ELEMENT} doesn't contained RSN IE, which means non-EAP
// AP. So verify carrier network is not checked, since EAP is currently required for a
// carrier network.
@@ -507,8 +622,7 @@
*/
@Test
public void testGetScanResultsForCarrierAp() throws Exception {
- IWifiScannerImpl scanner = setupClientInterfaceAndCreateMockWificondScanner();
- assertNotNull(scanner);
+ assertNotNull(mWifiScannerImpl);
// Include RSN IE to indicate EAP key management.
ByteArrayOutputStream out = new ByteArrayOutputStream();
@@ -516,7 +630,8 @@
out.write(TEST_INFO_ELEMENT_RSN);
NativeScanResult nativeScanResult = new NativeScanResult(MOCK_NATIVE_SCAN_RESULT);
nativeScanResult.infoElement = out.toByteArray();
- when(scanner.getScanResults()).thenReturn(new NativeScanResult[] {nativeScanResult});
+ when(mWifiScannerImpl.getScanResults()).thenReturn(
+ new NativeScanResult[] {nativeScanResult});
// AP associated with a carrier network.
int eapType = WifiEnterpriseConfig.Eap.SIM;
@@ -528,7 +643,7 @@
when(mCarrierNetworkConfig.getCarrierName(new String(nativeScanResult.ssid)))
.thenReturn(carrierName);
ArrayList<ScanDetail> returnedScanResults = mWificondControl.getScanResults(
- WificondControl.SCAN_TYPE_SINGLE_SCAN);
+ TEST_INTERFACE_NAME, WificondControl.SCAN_TYPE_SINGLE_SCAN);
assertEquals(1, returnedScanResults.size());
// Verify returned scan result.
ScanResult scanResult = returnedScanResults.get(0).getScanResult();
@@ -542,7 +657,7 @@
when(mCarrierNetworkConfig.isCarrierNetwork(new String(nativeScanResult.ssid)))
.thenReturn(false);
returnedScanResults = mWificondControl.getScanResults(
- WificondControl.SCAN_TYPE_SINGLE_SCAN);
+ TEST_INTERFACE_NAME, WificondControl.SCAN_TYPE_SINGLE_SCAN);
assertEquals(1, returnedScanResults.size());
// Verify returned scan result.
scanResult = returnedScanResults.get(0).getScanResult();
@@ -557,12 +672,10 @@
*/
@Test
public void testScan() throws Exception {
- IWifiScannerImpl scanner = setupClientInterfaceAndCreateMockWificondScanner();
-
- when(scanner.scan(any(SingleScanSettings.class))).thenReturn(true);
-
- assertTrue(mWificondControl.scan(SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_SET));
- verify(scanner).scan(argThat(new ScanMatcher(
+ when(mWifiScannerImpl.scan(any(SingleScanSettings.class))).thenReturn(true);
+ assertTrue(mWificondControl.scan(
+ TEST_INTERFACE_NAME, SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_SET));
+ verify(mWifiScannerImpl).scan(argThat(new ScanMatcher(
SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_SET)));
}
@@ -571,12 +684,9 @@
*/
@Test
public void testScanNullParameters() throws Exception {
- IWifiScannerImpl scanner = setupClientInterfaceAndCreateMockWificondScanner();
-
- when(scanner.scan(any(SingleScanSettings.class))).thenReturn(true);
-
- assertTrue(mWificondControl.scan(null, null));
- verify(scanner).scan(argThat(new ScanMatcher(null, null)));
+ when(mWifiScannerImpl.scan(any(SingleScanSettings.class))).thenReturn(true);
+ assertTrue(mWificondControl.scan(TEST_INTERFACE_NAME, null, null));
+ verify(mWifiScannerImpl).scan(argThat(new ScanMatcher(null, null)));
}
/**
@@ -584,11 +694,10 @@
*/
@Test
public void testScanFailure() throws Exception {
- IWifiScannerImpl scanner = setupClientInterfaceAndCreateMockWificondScanner();
-
- when(scanner.scan(any(SingleScanSettings.class))).thenReturn(false);
- assertFalse(mWificondControl.scan(SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_SET));
- verify(scanner).scan(any(SingleScanSettings.class));
+ when(mWifiScannerImpl.scan(any(SingleScanSettings.class))).thenReturn(false);
+ assertFalse(mWificondControl.scan(
+ TEST_INTERFACE_NAME, SCAN_FREQ_SET, SCAN_HIDDEN_NETWORK_SSID_SET));
+ verify(mWifiScannerImpl).scan(any(SingleScanSettings.class));
}
/**
@@ -596,11 +705,9 @@
*/
@Test
public void testStartPnoScan() throws Exception {
- IWifiScannerImpl scanner = setupClientInterfaceAndCreateMockWificondScanner();
-
- when(scanner.startPnoScan(any(PnoSettings.class))).thenReturn(true);
- assertTrue(mWificondControl.startPnoScan(TEST_PNO_SETTINGS));
- verify(scanner).startPnoScan(argThat(new PnoScanMatcher(TEST_PNO_SETTINGS)));
+ when(mWifiScannerImpl.startPnoScan(any(PnoSettings.class))).thenReturn(true);
+ assertTrue(mWificondControl.startPnoScan(TEST_INTERFACE_NAME, TEST_PNO_SETTINGS));
+ verify(mWifiScannerImpl).startPnoScan(argThat(new PnoScanMatcher(TEST_PNO_SETTINGS)));
}
/**
@@ -608,11 +715,9 @@
*/
@Test
public void testStopPnoScan() throws Exception {
- IWifiScannerImpl scanner = setupClientInterfaceAndCreateMockWificondScanner();
-
- when(scanner.stopPnoScan()).thenReturn(true);
- assertTrue(mWificondControl.stopPnoScan());
- verify(scanner).stopPnoScan();
+ when(mWifiScannerImpl.stopPnoScan()).thenReturn(true);
+ assertTrue(mWificondControl.stopPnoScan(TEST_INTERFACE_NAME));
+ verify(mWifiScannerImpl).stopPnoScan();
}
/**
@@ -620,11 +725,10 @@
*/
@Test
public void testStopPnoScanFailure() throws Exception {
- IWifiScannerImpl scanner = setupClientInterfaceAndCreateMockWificondScanner();
- when(scanner.stopPnoScan()).thenReturn(false);
- assertFalse(mWificondControl.stopPnoScan());
- verify(scanner).stopPnoScan();
+ when(mWifiScannerImpl.stopPnoScan()).thenReturn(false);
+ assertFalse(mWificondControl.stopPnoScan(TEST_INTERFACE_NAME));
+ verify(mWifiScannerImpl).stopPnoScan();
}
/**
@@ -633,10 +737,8 @@
*/
@Test
public void testScanResultEvent() throws Exception {
- IWifiScannerImpl scanner = setupClientInterfaceAndCreateMockWificondScanner();
-
ArgumentCaptor<IScanEvent> messageCaptor = ArgumentCaptor.forClass(IScanEvent.class);
- verify(scanner).subscribeScanEvents(messageCaptor.capture());
+ verify(mWifiScannerImpl).subscribeScanEvents(messageCaptor.capture());
IScanEvent scanEvent = messageCaptor.getValue();
assertNotNull(scanEvent);
scanEvent.OnScanResultReady();
@@ -650,10 +752,9 @@
*/
@Test
public void testScanFailedEvent() throws Exception {
- IWifiScannerImpl scanner = setupClientInterfaceAndCreateMockWificondScanner();
ArgumentCaptor<IScanEvent> messageCaptor = ArgumentCaptor.forClass(IScanEvent.class);
- verify(scanner).subscribeScanEvents(messageCaptor.capture());
+ verify(mWifiScannerImpl).subscribeScanEvents(messageCaptor.capture());
IScanEvent scanEvent = messageCaptor.getValue();
assertNotNull(scanEvent);
scanEvent.OnScanFailed();
@@ -667,10 +768,8 @@
*/
@Test
public void testPnoScanResultEvent() throws Exception {
- IWifiScannerImpl scanner = setupClientInterfaceAndCreateMockWificondScanner();
-
ArgumentCaptor<IPnoScanEvent> messageCaptor = ArgumentCaptor.forClass(IPnoScanEvent.class);
- verify(scanner).subscribePnoScanEvents(messageCaptor.capture());
+ verify(mWifiScannerImpl).subscribePnoScanEvents(messageCaptor.capture());
IPnoScanEvent pnoScanEvent = messageCaptor.getValue();
assertNotNull(pnoScanEvent);
pnoScanEvent.OnPnoNetworkFound();
@@ -682,10 +781,8 @@
*/
@Test
public void testPnoScanEventsForMetrics() throws Exception {
- IWifiScannerImpl scanner = setupClientInterfaceAndCreateMockWificondScanner();
-
ArgumentCaptor<IPnoScanEvent> messageCaptor = ArgumentCaptor.forClass(IPnoScanEvent.class);
- verify(scanner).subscribePnoScanEvents(messageCaptor.capture());
+ verify(mWifiScannerImpl).subscribePnoScanEvents(messageCaptor.capture());
IPnoScanEvent pnoScanEvent = messageCaptor.getValue();
assertNotNull(pnoScanEvent);
@@ -707,10 +804,8 @@
*/
@Test
public void testStartPnoScanForMetrics() throws Exception {
- IWifiScannerImpl scanner = setupClientInterfaceAndCreateMockWificondScanner();
-
- when(scanner.startPnoScan(any(PnoSettings.class))).thenReturn(false);
- assertFalse(mWificondControl.startPnoScan(TEST_PNO_SETTINGS));
+ when(mWifiScannerImpl.startPnoScan(any(PnoSettings.class))).thenReturn(false);
+ assertFalse(mWificondControl.startPnoScan(TEST_INTERFACE_NAME, TEST_PNO_SETTINGS));
verify(mWifiMetrics).incrementPnoScanStartAttempCount();
verify(mWifiMetrics).incrementPnoScanFailedCount();
}
@@ -720,42 +815,281 @@
*/
@Test
public void testAbortScan() throws Exception {
- IWifiScannerImpl scanner = setupClientInterfaceAndCreateMockWificondScanner();
-
- mWificondControl.abortScan();
- verify(scanner).abortScan();
+ mWificondControl.abortScan(TEST_INTERFACE_NAME);
+ verify(mWifiScannerImpl).abortScan();
}
/**
- * Helper method: create a mock IClientInterface which mocks all neccessary operations.
- * Returns a mock IClientInterface.
+ * Verifies successful soft ap start.
*/
- private IClientInterface getMockClientInterface() throws Exception {
- IClientInterface clientInterface = mock(IClientInterface.class);
- IWifiScannerImpl scanner = mock(IWifiScannerImpl.class);
+ @Test
+ public void testStartSoftApWithPskConfig() throws Exception {
+ testSetupInterfaceForSoftApMode();
+ WifiConfiguration config = new WifiConfiguration();
+ config.SSID = new String(TEST_SSID, StandardCharsets.UTF_8);
+ config.allowedKeyManagement.set(WPA_PSK);
+ config.preSharedKey = new String(TEST_PSK, StandardCharsets.UTF_8);
+ config.hiddenSSID = false;
+ config.apChannel = TEST_FREQUENCY;
- when(clientInterface.getWifiScannerImpl()).thenReturn(scanner);
+ when(mApInterface.writeHostapdConfig(
+ any(byte[].class), anyBoolean(), anyInt(), anyInt(), any(byte[].class)))
+ .thenReturn(true);
+ when(mApInterface.startHostapd(any())).thenReturn(true);
- return clientInterface;
+ assertTrue(mWificondControl.startSoftAp(
+ TEST_INTERFACE_NAME, config, mSoftApListener));
+ verify(mApInterface).writeHostapdConfig(
+ eq(TEST_SSID), eq(false), eq(TEST_FREQUENCY),
+ eq(IApInterface.ENCRYPTION_TYPE_WPA), eq(TEST_PSK));
+ verify(mApInterface).startHostapd(any());
}
/**
- * Helper method: Setup interface to client mode for mWificondControl.
- * Returns a mock IWifiScannerImpl.
+ * Verifies successful soft ap start.
*/
- private IWifiScannerImpl setupClientInterfaceAndCreateMockWificondScanner() throws Exception {
- IWificond wificond = mock(IWificond.class);
- IClientInterface clientInterface = mock(IClientInterface.class);
- IWifiScannerImpl scanner = mock(IWifiScannerImpl.class);
+ @Test
+ public void testStartSoftApWithOpenHiddenConfig() throws Exception {
+ testSetupInterfaceForSoftApMode();
+ WifiConfiguration config = new WifiConfiguration();
+ config.SSID = new String(TEST_SSID, StandardCharsets.UTF_8);
+ config.allowedKeyManagement.set(NONE);
+ config.hiddenSSID = true;
+ config.apChannel = TEST_FREQUENCY;
- when(mWifiInjector.makeWificond()).thenReturn(wificond);
- when(wificond.createClientInterface()).thenReturn(clientInterface);
- when(clientInterface.getWifiScannerImpl()).thenReturn(scanner);
- when(clientInterface.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
+ when(mApInterface.writeHostapdConfig(
+ any(byte[].class), anyBoolean(), anyInt(), anyInt(), any(byte[].class)))
+ .thenReturn(true);
+ when(mApInterface.startHostapd(any())).thenReturn(true);
- assertEquals(clientInterface, mWificondControl.setupDriverForClientMode());
+ assertTrue(mWificondControl.startSoftAp(
+ TEST_INTERFACE_NAME, config, mSoftApListener));
+ verify(mApInterface).writeHostapdConfig(
+ eq(TEST_SSID), eq(true), eq(TEST_FREQUENCY),
+ eq(IApInterface.ENCRYPTION_TYPE_NONE), eq(new byte[0]));
+ verify(mApInterface).startHostapd(any());
+ }
- return scanner;
+ /**
+ * Ensures that the Ap interface callbacks are forwarded to the
+ * SoftApListener used for starting soft AP.
+ */
+ @Test
+ public void testSoftApListenerInvocation() throws Exception {
+ testSetupInterfaceForSoftApMode();
+
+ WifiConfiguration config = new WifiConfiguration();
+ config.SSID = new String(TEST_SSID, StandardCharsets.UTF_8);
+
+ when(mApInterface.writeHostapdConfig(
+ any(byte[].class), anyBoolean(), anyInt(), anyInt(), any(byte[].class)))
+ .thenReturn(true);
+ when(mApInterface.startHostapd(any())).thenReturn(true);
+
+ final ArgumentCaptor<IApInterfaceEventCallback> apInterfaceCallbackCaptor =
+ ArgumentCaptor.forClass(IApInterfaceEventCallback.class);
+
+ assertTrue(mWificondControl.startSoftAp(
+ TEST_INTERFACE_NAME, config, mSoftApListener));
+ verify(mApInterface).writeHostapdConfig(
+ eq(TEST_SSID), anyBoolean(), anyInt(),
+ anyInt(), any(byte[].class));
+ verify(mApInterface).startHostapd(apInterfaceCallbackCaptor.capture());
+
+ int numStations = 5;
+ apInterfaceCallbackCaptor.getValue().onNumAssociatedStationsChanged(numStations);
+ verify(mSoftApListener).onNumAssociatedStationsChanged(eq(numStations));
+
+ }
+
+ /**
+ * Ensure that soft ap start fails when the interface is not setup.
+ */
+ @Test
+ public void testStartSoftApWithoutSetupInterface() throws Exception {
+ assertFalse(mWificondControl.startSoftAp(
+ TEST_INTERFACE_NAME, new WifiConfiguration(), mSoftApListener));
+ verify(mApInterface, never()).writeHostapdConfig(
+ any(byte[].class), anyBoolean(), anyInt(), anyInt(), any(byte[].class));
+ verify(mApInterface, never()).startHostapd(any());
+ }
+
+ /**
+ * Verifies soft ap start failure.
+ */
+ @Test
+ public void testStartSoftApFailDueToWriteConfigError() throws Exception {
+ testSetupInterfaceForSoftApMode();
+ WifiConfiguration config = new WifiConfiguration();
+ config.SSID = new String(TEST_SSID, StandardCharsets.UTF_8);
+
+ when(mApInterface.writeHostapdConfig(
+ any(byte[].class), anyBoolean(), anyInt(), anyInt(), any(byte[].class)))
+ .thenReturn(false);
+ when(mApInterface.startHostapd(any())).thenReturn(true);
+
+ assertFalse(mWificondControl.startSoftAp(
+ TEST_INTERFACE_NAME, config, mSoftApListener));
+ verify(mApInterface).writeHostapdConfig(
+ eq(TEST_SSID), anyBoolean(), anyInt(),
+ anyInt(), any(byte[].class));
+ verify(mApInterface, never()).startHostapd(any());
+ }
+
+ /**
+ * Verifies soft ap start failure.
+ */
+ @Test
+ public void testStartSoftApFailDueToStartError() throws Exception {
+ testSetupInterfaceForSoftApMode();
+ WifiConfiguration config = new WifiConfiguration();
+ config.SSID = new String(TEST_SSID, StandardCharsets.UTF_8);
+
+ when(mApInterface.writeHostapdConfig(
+ any(byte[].class), anyBoolean(), anyInt(), anyInt(), any(byte[].class)))
+ .thenReturn(true);
+ when(mApInterface.startHostapd(any())).thenReturn(false);
+
+ assertFalse(mWificondControl.startSoftAp(
+ TEST_INTERFACE_NAME, config, mSoftApListener));
+ verify(mApInterface).writeHostapdConfig(
+ eq(TEST_SSID), anyBoolean(), anyInt(),
+ anyInt(), any(byte[].class));
+ verify(mApInterface).startHostapd(any());
+ }
+
+ /**
+ * Verifies soft ap start failure.
+ */
+ @Test
+ public void testStartSoftApFailDueToExceptionInStart() throws Exception {
+ testSetupInterfaceForSoftApMode();
+ WifiConfiguration config = new WifiConfiguration();
+ config.SSID = new String(TEST_SSID, StandardCharsets.UTF_8);
+
+ when(mApInterface.writeHostapdConfig(
+ any(byte[].class), anyBoolean(), anyInt(), anyInt(), any(byte[].class)))
+ .thenReturn(true);
+ doThrow(new RemoteException()).when(mApInterface).startHostapd(any());
+
+ assertFalse(mWificondControl.startSoftAp(
+ TEST_INTERFACE_NAME, config, mSoftApListener));
+ verify(mApInterface).writeHostapdConfig(
+ eq(TEST_SSID), anyBoolean(), anyInt(),
+ anyInt(), any(byte[].class));
+ verify(mApInterface).startHostapd(any());
+ }
+
+ /**
+ * Verifies soft ap stop success.
+ */
+ @Test
+ public void testStopSoftAp() throws Exception {
+ testSetupInterfaceForSoftApMode();
+
+ when(mApInterface.stopHostapd()).thenReturn(true);
+
+ assertTrue(mWificondControl.stopSoftAp(TEST_INTERFACE_NAME));
+ verify(mApInterface).stopHostapd();
+ }
+
+ /**
+ * Ensure that soft ap stop fails when the interface is not setup.
+ */
+ @Test
+ public void testStopSoftApWithOutSetupInterface() throws Exception {
+ when(mApInterface.stopHostapd()).thenReturn(true);
+ assertFalse(mWificondControl.stopSoftAp(TEST_INTERFACE_NAME));
+ verify(mApInterface, never()).stopHostapd();
+ }
+
+ /**
+ * Verifies soft ap stop failure.
+ */
+ @Test
+ public void testStopSoftApFailDueToStopError() throws Exception {
+ testSetupInterfaceForSoftApMode();
+
+ when(mApInterface.stopHostapd()).thenReturn(false);
+
+ assertFalse(mWificondControl.stopSoftAp(TEST_INTERFACE_NAME));
+ verify(mApInterface).stopHostapd();
+ }
+
+ /**
+ * Verifies soft ap stop failure.
+ */
+ @Test
+ public void testStopSoftApFailDueToExceptionInStop() throws Exception {
+ testSetupInterfaceForSoftApMode();
+
+ doThrow(new RemoteException()).when(mApInterface).stopHostapd();
+
+ assertFalse(mWificondControl.stopSoftAp(TEST_INTERFACE_NAME));
+ verify(mApInterface).stopHostapd();
+ }
+
+ /**
+ * Verifies registration and invocation of wificond death handler.
+ */
+ @Test
+ public void testRegisterDeathHandler() throws Exception {
+ WifiNative.WificondDeathEventHandler handler =
+ mock(WifiNative.WificondDeathEventHandler.class);
+ assertTrue(mWificondControl.registerDeathHandler(handler));
+ mWificondControl.binderDied();
+ verify(handler).onDeath();
+ }
+
+ /**
+ * Verifies registration and invocation of 2 wificond death handlers.
+ */
+ @Test
+ public void testRegisterTwoDeathHandlers() throws Exception {
+ WifiNative.WificondDeathEventHandler handler1 =
+ mock(WifiNative.WificondDeathEventHandler.class);
+ WifiNative.WificondDeathEventHandler handler2 =
+ mock(WifiNative.WificondDeathEventHandler.class);
+ assertTrue(mWificondControl.registerDeathHandler(handler1));
+ assertFalse(mWificondControl.registerDeathHandler(handler2));
+ mWificondControl.binderDied();
+ verify(handler1).onDeath();
+ verify(handler2, never()).onDeath();
+ }
+
+ /**
+ * Verifies de-registration of wificond death handler.
+ */
+ @Test
+ public void testDeregisterDeathHandler() throws Exception {
+ WifiNative.WificondDeathEventHandler handler =
+ mock(WifiNative.WificondDeathEventHandler.class);
+ assertTrue(mWificondControl.registerDeathHandler(handler));
+ assertTrue(mWificondControl.deregisterDeathHandler());
+ mWificondControl.binderDied();
+ verify(handler, never()).onDeath();
+ }
+
+ /**
+ * Verifies handling of wificond death and ensures that all internal state is cleared and
+ * handlers are invoked.
+ */
+ @Test
+ public void testDeathHandling() throws Exception {
+ WifiNative.WificondDeathEventHandler handler =
+ mock(WifiNative.WificondDeathEventHandler.class);
+ assertTrue(mWificondControl.registerDeathHandler(handler));
+
+ testSetupInterfaceForClientMode();
+
+ mWificondControl.binderDied();
+ verify(handler).onDeath();
+
+ // The handles should be cleared after death, so these should retrieve new handles.
+ when(mWificond.enableSupplicant()).thenReturn(true);
+ assertTrue(mWificondControl.enableSupplicant());
+ verify(mWifiInjector, times(2)).makeWificond();
+ verify(mWificond).enableSupplicant();
}
// Create a ArgumentMatcher which captures a SingleScanSettings parameter and checks if it
diff --git a/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareDataPathStateManagerTest.java b/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareDataPathStateManagerTest.java
index 61143d9..f168c8c 100644
--- a/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareDataPathStateManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareDataPathStateManagerTest.java
@@ -1285,8 +1285,9 @@
NetworkCapabilities nc = new NetworkCapabilities();
nc.clearAll();
nc.addTransportType(NetworkCapabilities.TRANSPORT_WIFI_AWARE);
- nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN).addCapability(
- NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
+ nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
nc.setNetworkSpecifier(ns);
nc.setLinkUpstreamBandwidthKbps(1);
nc.setLinkDownstreamBandwidthKbps(1);
diff --git a/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareNativeApiTest.java b/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareNativeApiTest.java
index 9564189..dfec005 100644
--- a/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareNativeApiTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareNativeApiTest.java
@@ -21,6 +21,7 @@
import static org.mockito.ArgumentMatchers.anyShort;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -28,9 +29,14 @@
import android.hardware.wifi.V1_0.NanBandIndex;
import android.hardware.wifi.V1_0.NanConfigRequest;
import android.hardware.wifi.V1_0.NanEnableRequest;
+import android.hardware.wifi.V1_0.NanPublishRequest;
+import android.hardware.wifi.V1_0.NanRangingIndication;
+import android.hardware.wifi.V1_0.NanSubscribeRequest;
import android.hardware.wifi.V1_0.WifiStatus;
import android.hardware.wifi.V1_0.WifiStatusCode;
import android.net.wifi.aware.ConfigRequest;
+import android.net.wifi.aware.PublishConfig;
+import android.net.wifi.aware.SubscribeConfig;
import android.os.RemoteException;
import org.junit.Before;
@@ -67,6 +73,8 @@
status.code = WifiStatusCode.SUCCESS;
when(mIWifiNanIfaceMock.enableRequest(anyShort(), any())).thenReturn(status);
when(mIWifiNanIfaceMock.configRequest(anyShort(), any())).thenReturn(status);
+ when(mIWifiNanIfaceMock.startPublishRequest(anyShort(), any())).thenReturn(status);
+ when(mIWifiNanIfaceMock.startSubscribeRequest(anyShort(), any())).thenReturn(status);
mDut = new WifiAwareNativeApi(mWifiAwareNativeManagerMock);
}
@@ -164,6 +172,105 @@
.validDiscoveryWindowIntervalVal));
}
+ @Test
+ public void testDiscoveryRangingSettings() throws RemoteException {
+ short tid = 666;
+ byte pid = 34;
+ int minDistanceMm = 100;
+ int maxDistanceMm = 555;
+ // TODO: b/69428593 remove once HAL is converted from CM to MM
+ short minDistanceCm = (short) (minDistanceMm / 10);
+ short maxDistanceCm = (short) (maxDistanceMm / 10);
+
+ ArgumentCaptor<NanPublishRequest> pubCaptor = ArgumentCaptor.forClass(
+ NanPublishRequest.class);
+ ArgumentCaptor<NanSubscribeRequest> subCaptor = ArgumentCaptor.forClass(
+ NanSubscribeRequest.class);
+
+ PublishConfig pubDefault = new PublishConfig.Builder().setServiceName("XXX").build();
+ PublishConfig pubWithRanging = new PublishConfig.Builder().setServiceName(
+ "XXX").setRangingEnabled(true).build();
+ SubscribeConfig subDefault = new SubscribeConfig.Builder().setServiceName("XXX").build();
+ SubscribeConfig subWithMin = new SubscribeConfig.Builder().setServiceName(
+ "XXX").setMinDistanceMm(minDistanceMm).build();
+ SubscribeConfig subWithMax = new SubscribeConfig.Builder().setServiceName(
+ "XXX").setMaxDistanceMm(maxDistanceMm).build();
+ SubscribeConfig subWithMinMax = new SubscribeConfig.Builder().setServiceName(
+ "XXX").setMinDistanceMm(minDistanceMm).setMaxDistanceMm(maxDistanceMm).build();
+
+ mDut.publish(tid, pid, pubDefault);
+ mDut.publish(tid, pid, pubWithRanging);
+ mDut.subscribe(tid, pid, subDefault);
+ mDut.subscribe(tid, pid, subWithMin);
+ mDut.subscribe(tid, pid, subWithMax);
+ mDut.subscribe(tid, pid, subWithMinMax);
+
+ verify(mIWifiNanIfaceMock, times(2)).startPublishRequest(eq(tid), pubCaptor.capture());
+ verify(mIWifiNanIfaceMock, times(4)).startSubscribeRequest(eq(tid), subCaptor.capture());
+
+ NanPublishRequest halPubReq;
+ NanSubscribeRequest halSubReq;
+
+ // pubDefault
+ halPubReq = pubCaptor.getAllValues().get(0);
+ collector.checkThat("pubDefault.baseConfigs.sessionId", pid,
+ equalTo(halPubReq.baseConfigs.sessionId));
+ collector.checkThat("pubDefault.baseConfigs.rangingRequired", false,
+ equalTo(halPubReq.baseConfigs.rangingRequired));
+
+ // pubWithRanging
+ halPubReq = pubCaptor.getAllValues().get(1);
+ collector.checkThat("pubWithRanging.baseConfigs.sessionId", pid,
+ equalTo(halPubReq.baseConfigs.sessionId));
+ collector.checkThat("pubWithRanging.baseConfigs.rangingRequired", true,
+ equalTo(halPubReq.baseConfigs.rangingRequired));
+
+ // subDefault
+ halSubReq = subCaptor.getAllValues().get(0);
+ collector.checkThat("subDefault.baseConfigs.sessionId", pid,
+ equalTo(halSubReq.baseConfigs.sessionId));
+ collector.checkThat("subDefault.baseConfigs.rangingRequired", false,
+ equalTo(halSubReq.baseConfigs.rangingRequired));
+
+ // subWithMin
+ halSubReq = subCaptor.getAllValues().get(1);
+ collector.checkThat("subWithMin.baseConfigs.sessionId", pid,
+ equalTo(halSubReq.baseConfigs.sessionId));
+ collector.checkThat("subWithMin.baseConfigs.rangingRequired", true,
+ equalTo(halSubReq.baseConfigs.rangingRequired));
+ collector.checkThat("subWithMin.baseConfigs.configRangingIndications",
+ NanRangingIndication.INGRESS_MET_MASK,
+ equalTo(halSubReq.baseConfigs.configRangingIndications));
+ collector.checkThat("subWithMin.baseConfigs.distanceIngressCm", minDistanceCm,
+ equalTo(halSubReq.baseConfigs.distanceIngressCm));
+
+ // subWithMax
+ halSubReq = subCaptor.getAllValues().get(2);
+ collector.checkThat("subWithMax.baseConfigs.sessionId", pid,
+ equalTo(halSubReq.baseConfigs.sessionId));
+ collector.checkThat("subWithMax.baseConfigs.rangingRequired", true,
+ equalTo(halSubReq.baseConfigs.rangingRequired));
+ collector.checkThat("subWithMax.baseConfigs.configRangingIndications",
+ NanRangingIndication.EGRESS_MET_MASK,
+ equalTo(halSubReq.baseConfigs.configRangingIndications));
+ collector.checkThat("subWithMin.baseConfigs.distanceEgressCm", maxDistanceCm,
+ equalTo(halSubReq.baseConfigs.distanceEgressCm));
+
+ // subWithMinMax
+ halSubReq = subCaptor.getAllValues().get(3);
+ collector.checkThat("subWithMinMax.baseConfigs.sessionId", pid,
+ equalTo(halSubReq.baseConfigs.sessionId));
+ collector.checkThat("subWithMinMax.baseConfigs.rangingRequired", true,
+ equalTo(halSubReq.baseConfigs.rangingRequired));
+ collector.checkThat("subWithMinMax.baseConfigs.configRangingIndications",
+ NanRangingIndication.INGRESS_MET_MASK | NanRangingIndication.EGRESS_MET_MASK,
+ equalTo(halSubReq.baseConfigs.configRangingIndications));
+ collector.checkThat("subWithMin.baseConfigs.distanceIngressCm", minDistanceCm,
+ equalTo(halSubReq.baseConfigs.distanceIngressCm));
+ collector.checkThat("subWithMin.baseConfigs.distanceEgressCm", maxDistanceCm,
+ equalTo(halSubReq.baseConfigs.distanceEgressCm));
+ }
+
// utilities
private void setPowerConfigurationParams(byte interactive5, byte interactive24, byte idle5,
diff --git a/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareNativeManagerTest.java b/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareNativeManagerTest.java
index ba984b8..122d6e6 100644
--- a/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareNativeManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareNativeManagerTest.java
@@ -28,6 +28,7 @@
import android.hardware.wifi.V1_0.IfaceType;
import android.hardware.wifi.V1_0.WifiStatus;
import android.hardware.wifi.V1_0.WifiStatusCode;
+import android.os.Handler;
import com.android.server.wifi.HalDeviceManager;
@@ -49,6 +50,7 @@
@Mock private HalDeviceManager mHalDeviceManager;
@Mock private WifiAwareNativeCallback mWifiAwareNativeCallback;
@Mock private IWifiNanIface mWifiNanIfaceMock;
+ @Mock private Handler mHandlerMock;
private ArgumentCaptor<HalDeviceManager.ManagerStatusListener> mManagerStatusListenerCaptor =
ArgumentCaptor.forClass(HalDeviceManager.ManagerStatusListener.class);
private ArgumentCaptor<HalDeviceManager.InterfaceDestroyedListener>
@@ -73,7 +75,7 @@
mDut = new WifiAwareNativeManager(mWifiAwareStateManagerMock,
mHalDeviceManager, mWifiAwareNativeCallback);
- mDut.start();
+ mDut.start(mHandlerMock);
mInOrder = inOrder(mWifiAwareStateManagerMock, mHalDeviceManager);
}
@@ -106,7 +108,7 @@
mManagerStatusListenerCaptor.getValue().onStatusChanged();
mInOrder.verify(mHalDeviceManager).registerInterfaceAvailableForRequestListener(
- eq(IfaceType.NAN), mAvailListenerCaptor.capture(), any());
+ eq(IfaceType.NAN), mAvailListenerCaptor.capture(), any(Handler.class));
mAvailListenerCaptor.getValue().onAvailableForRequest();
mInOrder.verify(mHalDeviceManager).createNanIface(
@@ -137,7 +139,7 @@
mManagerStatusListenerCaptor.getValue().onStatusChanged();
mInOrder.verify(mHalDeviceManager).registerInterfaceAvailableForRequestListener(
- eq(IfaceType.NAN), mAvailListenerCaptor.capture(), any());
+ eq(IfaceType.NAN), mAvailListenerCaptor.capture(), any(Handler.class));
mAvailListenerCaptor.getValue().onAvailableForRequest();
mInOrder.verify(mHalDeviceManager).createNanIface(
@@ -147,7 +149,7 @@
equalTo(mWifiNanIfaceMock));
// 8 onDestroyed: disable usage
- mDestroyedListenerCaptor.getValue().onDestroyed();
+ mDestroyedListenerCaptor.getValue().onDestroyed(new String());
mInOrder.verify(mWifiAwareStateManagerMock).disableUsage();
collector.checkThat("null interface", mDut.getWifiNanIface(), nullValue());
diff --git a/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareRttStateManagerTest.java b/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareRttStateManagerTest.java
deleted file mode 100644
index 3df62f3..0000000
--- a/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareRttStateManagerTest.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wifi.aware;
-
-import static org.hamcrest.core.IsEqual.equalTo;
-import static org.hamcrest.core.IsNull.nullValue;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.net.wifi.IRttManager;
-import android.net.wifi.RttManager;
-import android.os.Handler;
-import android.os.Message;
-import android.os.test.TestLooper;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import com.android.internal.util.test.BidirectionalAsyncChannelServer;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ErrorCollector;
-import org.mockito.ArgumentCaptor;
-import org.mockito.InOrder;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-/**
- * Unit test harness for WifiAwareManager class.
- */
-@SmallTest
-public class WifiAwareRttStateManagerTest {
- private WifiAwareRttStateManager mDut;
- private TestLooper mTestLooper;
-
- @Mock
- private Context mMockContext;
-
- @Mock
- private Handler mMockHandler;
-
- @Mock
- private IRttManager mMockRttService;
-
- @Rule
- public ErrorCollector collector = new ErrorCollector();
-
- /**
- * Initialize mocks.
- */
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
-
- mDut = new WifiAwareRttStateManager();
- mTestLooper = new TestLooper();
- BidirectionalAsyncChannelServer server = new BidirectionalAsyncChannelServer(
- mMockContext, mTestLooper.getLooper(), mMockHandler);
- when(mMockRttService.getMessenger(null, new int[1])).thenReturn(server.getMessenger());
-
- mDut.startWithRttService(mMockContext, mTestLooper.getLooper(), mMockRttService);
- }
-
- /**
- * Validates that startRanging flow works: (1) start ranging, (2) get success callback - pass
- * to client (while nulling BSSID info), (3) get fail callback - ignored (since client
- * cleaned-out after first callback).
- */
- @Test
- public void testStartRanging() throws Exception {
- final int rangingId = 1234;
- WifiAwareClientState mockClient = mock(WifiAwareClientState.class);
- RttManager.RttParams[] params = new RttManager.RttParams[1];
- params[0] = new RttManager.RttParams();
- RttManager.ParcelableRttResults results =
- new RttManager.ParcelableRttResults(new RttManager.RttResult[2]);
- results.mResults[0] = new RttManager.RttResult();
- results.mResults[0].bssid = "something non-null";
- results.mResults[1] = new RttManager.RttResult();
- results.mResults[1].bssid = "really really non-null";
-
- ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
- ArgumentCaptor<RttManager.ParcelableRttResults> rttResultsCaptor =
- ArgumentCaptor.forClass(RttManager.ParcelableRttResults.class);
-
- InOrder inOrder = inOrder(mMockHandler, mockClient);
-
- // (1) start ranging
- mDut.startRanging(rangingId, mockClient, params);
- mTestLooper.dispatchAll();
- inOrder.verify(mMockHandler).handleMessage(messageCaptor.capture());
- Message msg = messageCaptor.getValue();
- collector.checkThat("msg.what=RttManager.CMD_OP_START_RANGING", msg.what,
- equalTo(RttManager.CMD_OP_START_RANGING));
- collector.checkThat("rangingId", msg.arg2, equalTo(rangingId));
- collector.checkThat("RTT params", ((RttManager.ParcelableRttParams) msg.obj).mParams,
- equalTo(params));
-
- // (2) get success callback - pass to client
- Message successMessage = Message.obtain();
- successMessage.what = RttManager.CMD_OP_SUCCEEDED;
- successMessage.arg2 = rangingId;
- successMessage.obj = results;
- msg.replyTo.send(successMessage);
- mTestLooper.dispatchAll();
- inOrder.verify(mockClient).onRangingSuccess(eq(rangingId), rttResultsCaptor.capture());
- collector.checkThat("ParcelableRttResults object", results,
- equalTo(rttResultsCaptor.getValue()));
- collector.checkThat("RttResults[0].bssid null",
- rttResultsCaptor.getValue().mResults[0].bssid, nullValue());
- collector.checkThat("RttResults[1].bssid null",
- rttResultsCaptor.getValue().mResults[1].bssid, nullValue());
-
- // (3) get fail callback - ignored
- Message failMessage = Message.obtain();
- failMessage.what = RttManager.CMD_OP_ABORTED;
- failMessage.arg2 = rangingId;
- msg.replyTo.send(failMessage);
- mTestLooper.dispatchAll();
-
- verifyNoMoreInteractions(mMockHandler, mockClient);
- }
-}
diff --git a/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareServiceImplTest.java b/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareServiceImplTest.java
index d666262..f323110 100644
--- a/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareServiceImplTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareServiceImplTest.java
@@ -16,28 +16,31 @@
package com.android.server.wifi.aware;
-import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
-import android.net.wifi.RttManager;
import android.net.wifi.aware.Characteristics;
import android.net.wifi.aware.ConfigRequest;
import android.net.wifi.aware.IWifiAwareDiscoverySessionCallback;
import android.net.wifi.aware.IWifiAwareEventCallback;
+import android.net.wifi.aware.IWifiAwareMacAddressProvider;
import android.net.wifi.aware.PublishConfig;
import android.net.wifi.aware.SubscribeConfig;
import android.os.HandlerThread;
import android.os.IBinder;
+import android.os.RemoteException;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.SparseArray;
import android.util.SparseIntArray;
@@ -52,6 +55,9 @@
import org.mockito.MockitoAnnotations;
import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
/**
* Unit test harness for WifiAwareStateManager.
@@ -82,8 +88,6 @@
@Mock private WifiAwareMetrics mAwareMetricsMock;
@Mock private WifiPermissionsWrapper mPermissionsWrapperMock;
- private HandlerThread mHandlerThread;
-
/**
* Using instead of spy to avoid native crash failures - possibly due to
* spy's copying of state.
@@ -510,63 +514,47 @@
0);
}
- /**
- * Validate startRanging() - correct pass-through args
- */
@Test
- public void testStartRanging() {
- int clientId = doConnect();
- int sessionId = 65345;
- RttManager.ParcelableRttParams params =
- new RttManager.ParcelableRttParams(new RttManager.RttParams[1]);
-
- ArgumentCaptor<RttManager.RttParams[]> paramsCaptor =
- ArgumentCaptor.forClass(RttManager.RttParams[].class);
-
- int rangingId = mDut.startRanging(clientId, sessionId, params);
-
- verify(mAwareStateManagerMock).startRanging(eq(clientId), eq(sessionId),
- paramsCaptor.capture(), eq(rangingId));
-
- assertArrayEquals(paramsCaptor.getValue(), params.mParams);
- }
-
- /**
- * Validates that sequential startRanging() calls return increasing ranging IDs.
- */
- @Test
- public void testRangingIdIncrementing() {
- int loopCount = 100;
- int clientId = doConnect();
- int sessionId = 65345;
- RttManager.ParcelableRttParams params =
- new RttManager.ParcelableRttParams(new RttManager.RttParams[1]);
-
- int prevRangingId = 0;
- for (int i = 0; i < loopCount; ++i) {
- int rangingId = mDut.startRanging(clientId, sessionId, params);
- if (i != 0) {
- assertTrue("Client ID incrementing", rangingId > prevRangingId);
+ public void testRequestMacAddress() {
+ int uid = 1005;
+ List<Integer> list = new ArrayList<>();
+ IWifiAwareMacAddressProvider callback = new IWifiAwareMacAddressProvider() { // dummy
+ @Override
+ public void macAddress(Map peerIdToMacMap) throws RemoteException {
+ // empty
}
- prevRangingId = rangingId;
- }
+
+ @Override
+ public IBinder asBinder() {
+ return null;
+ }
+ };
+
+ mDut.requestMacAddresses(uid, list, callback);
+
+ verify(mAwareStateManagerMock).requestMacAddresses(uid, list, callback);
}
- /**
- * Validates that startRanging() requires a non-empty list
+ @Test(expected = SecurityException.class)
+ public void testRequestMacAddressWithoutPermission() {
+ doThrow(new SecurityException()).when(mContextMock).enforceCallingOrSelfPermission(
+ eq(Manifest.permission.NETWORK_STACK), anyString());
+
+ mDut.requestMacAddresses(1005, new ArrayList<>(), new IWifiAwareMacAddressProvider() {
+ @Override
+ public void macAddress(Map peerIdToMacMap) throws RemoteException {
+ }
+
+ @Override
+ public IBinder asBinder() {
+ return null;
+ }
+ });
+ }
+
+ /*
+ * Utilities
*/
- @Test(expected = IllegalArgumentException.class)
- public void testStartRangingZeroArgs() {
- int clientId = doConnect();
- int sessionId = 65345;
- RttManager.ParcelableRttParams params =
- new RttManager.ParcelableRttParams(new RttManager.RttParams[0]);
-
- ArgumentCaptor<RttManager.RttParams[]> paramsCaptor =
- ArgumentCaptor.forClass(RttManager.RttParams[].class);
-
- int rangingId = mDut.startRanging(clientId, sessionId, params);
- }
/*
* Tests of internal state of WifiAwareServiceImpl: very limited (not usually
@@ -574,7 +562,6 @@
* appropriately. Alternatively would cause issues with memory leaks or
* information leak between sessions.
*/
-
private void validateInternalStateCleanedUp(int clientId) throws Exception {
int uidEntry = getInternalStateUid(clientId);
assertEquals(-1, uidEntry);
@@ -583,17 +570,13 @@
assertEquals(null, dr);
}
- /*
- * Utilities
- */
-
private void doBadPublishConfiguration(String serviceName, byte[] ssi, byte[] matchFilter)
throws IllegalArgumentException {
// using the hidden constructor since may be passing invalid parameters which would be
// caught by the Builder. Want to test whether service side will catch invalidly
// constructed configs.
PublishConfig publishConfig = new PublishConfig(serviceName.getBytes(), ssi, matchFilter,
- PublishConfig.PUBLISH_TYPE_UNSOLICITED, 0, true);
+ PublishConfig.PUBLISH_TYPE_UNSOLICITED, 0, true, false);
int clientId = doConnect();
IWifiAwareDiscoverySessionCallback mockCallback = mock(
IWifiAwareDiscoverySessionCallback.class);
@@ -609,7 +592,7 @@
// caught by the Builder. Want to test whether service side will catch invalidly
// constructed configs.
SubscribeConfig subscribeConfig = new SubscribeConfig(serviceName.getBytes(), ssi,
- matchFilter, SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE, 0, true);
+ matchFilter, SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE, 0, true, false, 0, false, 0);
int clientId = doConnect();
IWifiAwareDiscoverySessionCallback mockCallback = mock(
IWifiAwareDiscoverySessionCallback.class);
diff --git a/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareStateManagerTest.java b/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareStateManagerTest.java
index faa87df..fb11789 100644
--- a/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareStateManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareStateManagerTest.java
@@ -20,6 +20,7 @@
import static org.hamcrest.core.IsNull.notNullValue;
import static org.hamcrest.core.IsNull.nullValue;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -45,19 +46,22 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
+import android.hardware.wifi.V1_0.NanRangingIndication;
import android.hardware.wifi.V1_0.NanStatusType;
import android.net.ConnectivityManager;
-import android.net.wifi.RttManager;
import android.net.wifi.aware.ConfigRequest;
import android.net.wifi.aware.IWifiAwareDiscoverySessionCallback;
import android.net.wifi.aware.IWifiAwareEventCallback;
+import android.net.wifi.aware.IWifiAwareMacAddressProvider;
import android.net.wifi.aware.PublishConfig;
import android.net.wifi.aware.SubscribeConfig;
import android.net.wifi.aware.WifiAwareManager;
import android.os.Handler;
+import android.os.IBinder;
import android.os.IPowerManager;
import android.os.Message;
import android.os.PowerManager;
+import android.os.RemoteException;
import android.os.UserHandle;
import android.os.test.TestLooper;
import android.test.suitebuilder.annotation.SmallTest;
@@ -80,9 +84,11 @@
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Field;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
+import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
@@ -99,7 +105,6 @@
@Mock private WifiAwareNativeApi mMockNative;
@Mock private Context mMockContext;
@Mock private AppOpsManager mMockAppOpsManager;
- @Mock private WifiAwareRttStateManager mMockAwareRttStateManager;
@Mock private WifiAwareMetrics mAwareMetricsMock;
@Mock private WifiPermissionsWrapper mPermissionsWrapperMock;
TestAlarmManager mAlarmManager;
@@ -156,7 +161,7 @@
mMockLooper.dispatchAll();
verify(mMockContext).registerReceiver(bcastRxCaptor.capture(), any(IntentFilter.class));
mPowerBcastReceiver = bcastRxCaptor.getValue();
- installMocksInStateManager(mDut, mMockAwareRttStateManager, mMockAwareDataPathStatemanager);
+ installMocksInStateManager(mDut, mMockAwareDataPathStatemanager);
when(mMockNative.enableAndConfigure(anyShort(), any(), anyBoolean(),
anyBoolean(), anyBoolean(), anyBoolean())).thenReturn(true);
@@ -198,6 +203,128 @@
}
/**
+ * Test the PeerHandle -> MAC address API:
+ * - Start up discovery of 2 sessions
+ * - Get multiple matches (PeerHandles)
+ * - Request translation as UID of sesssion #1 for PeerHandles of the same UID + of the other
+ * discovery session (to which we shouldn't have access) + invalid PeerHandle.
+ * -> validate results
+ */
+ @Test
+ public void testRequestMacAddresses() throws Exception {
+ final int clientId1 = 1005;
+ final int clientId2 = 1006;
+ final int uid1 = 1000;
+ final int uid2 = 1001;
+ final int pid1 = 2000;
+ final int pid2 = 2001;
+ final String callingPackage = "com.google.somePackage";
+ final String serviceName = "some-service-name";
+ final byte subscribeId1 = 15;
+ final byte subscribeId2 = 16;
+ final int requestorIdBase = 22;
+ final byte[] peerMac1 = HexEncoding.decode("060708090A0B".toCharArray(), false);
+ final byte[] peerMac2 = HexEncoding.decode("010203040506".toCharArray(), false);
+ final byte[] peerMac3 = HexEncoding.decode("AABBCCDDEEFF".toCharArray(), false);
+ final int distance = 10;
+
+ ConfigRequest configRequest = new ConfigRequest.Builder().build();
+ SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().setServiceName(serviceName)
+ .build();
+
+ IWifiAwareEventCallback mockCallback1 = mock(IWifiAwareEventCallback.class);
+ IWifiAwareEventCallback mockCallback2 = mock(IWifiAwareEventCallback.class);
+ IWifiAwareDiscoverySessionCallback mockSessionCallback1 = mock(
+ IWifiAwareDiscoverySessionCallback.class);
+ IWifiAwareDiscoverySessionCallback mockSessionCallback2 = mock(
+ IWifiAwareDiscoverySessionCallback.class);
+ ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class);
+ ArgumentCaptor<Integer> sessionId = ArgumentCaptor.forClass(Integer.class);
+ ArgumentCaptor<Integer> peerIdCaptor = ArgumentCaptor.forClass(Integer.class);
+ InOrder inOrder = inOrder(mockCallback1, mockCallback2, mockSessionCallback1,
+ mockSessionCallback2, mMockNative);
+
+ // (0) enable
+ mDut.enableUsage();
+ mMockLooper.dispatchAll();
+ inOrder.verify(mMockNative).getCapabilities(transactionId.capture());
+ mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities());
+ mMockLooper.dispatchAll();
+
+ // (1) connect 2 clients
+ mDut.connect(clientId1, uid1, pid1, callingPackage, mockCallback1, configRequest, false);
+ mMockLooper.dispatchAll();
+ inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(),
+ eq(configRequest), eq(false), eq(true), eq(true), eq(false));
+ mDut.onConfigSuccessResponse(transactionId.getValue());
+ mMockLooper.dispatchAll();
+ inOrder.verify(mockCallback1).onConnectSuccess(clientId1);
+
+ mDut.connect(clientId2, uid2, pid2, callingPackage, mockCallback2, configRequest, false);
+ mMockLooper.dispatchAll();
+ inOrder.verify(mockCallback2).onConnectSuccess(clientId2);
+
+ // (2) subscribe both clients
+ mDut.subscribe(clientId1, subscribeConfig, mockSessionCallback1);
+ mMockLooper.dispatchAll();
+ inOrder.verify(mMockNative).subscribe(transactionId.capture(), eq((byte) 0),
+ eq(subscribeConfig));
+ mDut.onSessionConfigSuccessResponse(transactionId.getValue(), false, subscribeId1);
+ mMockLooper.dispatchAll();
+ inOrder.verify(mockSessionCallback1).onSessionStarted(sessionId.capture());
+
+ mDut.subscribe(clientId2, subscribeConfig, mockSessionCallback2);
+ mMockLooper.dispatchAll();
+ inOrder.verify(mMockNative).subscribe(transactionId.capture(), eq((byte) 0),
+ eq(subscribeConfig));
+ mDut.onSessionConfigSuccessResponse(transactionId.getValue(), false, subscribeId2);
+ mMockLooper.dispatchAll();
+ inOrder.verify(mockSessionCallback2).onSessionStarted(sessionId.capture());
+
+ // (3) 2 matches on session 1 (second one with distance), 1 match on session 2
+ mDut.onMatchNotification(subscribeId1, requestorIdBase, peerMac1, null, null, 0, 0);
+ mDut.onMatchNotification(subscribeId1, requestorIdBase + 1, peerMac2, null, null,
+ NanRangingIndication.INGRESS_MET_MASK, distance);
+ mMockLooper.dispatchAll();
+ inOrder.verify(mockSessionCallback1).onMatch(peerIdCaptor.capture(), isNull(),
+ isNull());
+ inOrder.verify(mockSessionCallback1).onMatchWithDistance(peerIdCaptor.capture(), isNull(),
+ isNull(), eq(distance));
+ int peerId1 = peerIdCaptor.getAllValues().get(0);
+ int peerId2 = peerIdCaptor.getAllValues().get(1);
+
+ mDut.onMatchNotification(subscribeId2, requestorIdBase + 2, peerMac3, null, null, 0, 0);
+ mMockLooper.dispatchAll();
+ inOrder.verify(mockSessionCallback2).onMatch(peerIdCaptor.capture(), isNull(), isNull());
+ int peerId3 = peerIdCaptor.getAllValues().get(0);
+
+ // request MAC addresses
+ List<Integer> request = new ArrayList<>();
+ request.add(peerId1);
+ request.add(peerId2);
+ request.add(peerId3); // for uid2: so should not be in results
+ request.add(peerId1 * 20 + peerId2 + peerId3); // garbage values != to any
+ Mutable<Map> response = new Mutable<>();
+ mDut.requestMacAddresses(uid1, request, new IWifiAwareMacAddressProvider() {
+ @Override
+ public void macAddress(Map peerIdToMacMap) throws RemoteException {
+ response.value = peerIdToMacMap;
+ }
+
+ @Override
+ public IBinder asBinder() {
+ return null;
+ }
+ });
+ mMockLooper.dispatchAll();
+
+ assertNotEquals("Non-null result", null, response.value);
+ assertEquals("Number of results", 2, response.value.size());
+ assertEquals("Results[peerId1]", peerMac1, response.value.get(peerId1));
+ assertEquals("Results[peerId2]", peerMac2, response.value.get(peerId2));
+ }
+
+ /**
* Validate that Aware data-path interfaces are brought up and down correctly.
*/
@Test
@@ -1240,7 +1367,7 @@
// (2) match
mDut.onMatchNotification(subscribeId, requestorId, peerMac, peerSsi.getBytes(),
- peerMatchFilter.getBytes());
+ peerMatchFilter.getBytes(), 0, 0);
mMockLooper.dispatchAll();
inOrder.verify(mockSessionCallback).onMatch(peerIdCaptor.capture(), eq(peerSsi.getBytes()),
eq(peerMatchFilter.getBytes()));
@@ -1540,7 +1667,7 @@
eq(subscribeConfig));
mDut.onSessionConfigSuccessResponse(transactionId.getValue(), false, subscribeId);
mDut.onMatchNotification(subscribeId, requestorId, peerMac, peerSsi.getBytes(),
- peerMatchFilter.getBytes());
+ peerMatchFilter.getBytes(), 0, 0);
mMockLooper.dispatchAll();
inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture());
inOrder.verify(mockSessionCallback).onMatch(peerIdCaptor.capture(), eq(peerSsi.getBytes()),
@@ -1609,7 +1736,7 @@
eq(subscribeConfig));
mDut.onSessionConfigSuccessResponse(transactionId.getValue(), false, subscribeId);
mDut.onMatchNotification(subscribeId, requestorId, peerMac, peerSsi.getBytes(),
- peerMatchFilter.getBytes());
+ peerMatchFilter.getBytes(), 0, 0);
mMockLooper.dispatchAll();
inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture());
inOrder.verify(mockSessionCallback).onMatch(peerIdCaptor.capture(), eq(peerSsi.getBytes()),
@@ -1735,7 +1862,7 @@
eq(subscribeConfig));
mDut.onSessionConfigSuccessResponse(transactionId.getValue(), false, subscribeId);
mDut.onMatchNotification(subscribeId, requestorId, peerMac, peerSsi.getBytes(),
- peerMatchFilter.getBytes());
+ peerMatchFilter.getBytes(), 0, 0);
mMockLooper.dispatchAll();
inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture());
inOrder.verify(mockSessionCallback).onMatch(peerIdCaptor.capture(), eq(peerSsi.getBytes()),
@@ -1822,7 +1949,7 @@
eq(subscribeConfig));
mDut.onSessionConfigSuccessResponse(transactionId.getValue(), false, subscribeId);
mDut.onMatchNotification(subscribeId, requestorId, peerMac, peerSsi.getBytes(),
- peerMatchFilter.getBytes());
+ peerMatchFilter.getBytes(), 0, 0);
mMockLooper.dispatchAll();
inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture());
inOrder.verify(mockSessionCallback).onMatch(peerIdCaptor.capture(), eq(peerSsi.getBytes()),
@@ -1913,7 +2040,7 @@
inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture());
// (2) match
- mDut.onMatchNotification(subscribeId, requestorId, peerMac, null, null);
+ mDut.onMatchNotification(subscribeId, requestorId, peerMac, null, null, 0, 0);
mMockLooper.dispatchAll();
inOrder.verify(mockSessionCallback).onMatch(peerIdCaptor.capture(), isNull(), isNull());
@@ -2010,7 +2137,7 @@
inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture());
// (2) match
- mDut.onMatchNotification(subscribeId, requestorId, peerMac, null, null);
+ mDut.onMatchNotification(subscribeId, requestorId, peerMac, null, null, 0, 0);
mMockLooper.dispatchAll();
inOrder.verify(mockSessionCallback).onMatch(peerIdCaptor.capture(), isNull(), isNull());
@@ -2143,7 +2270,7 @@
// (2) match
mDut.onMatchNotification(subscribeId, requestorId, peerMac, peerSsi.getBytes(),
- peerMatchFilter.getBytes());
+ peerMatchFilter.getBytes(), 0, 0);
mMockLooper.dispatchAll();
inOrder.verify(mockSessionCallback).onMatch(peerIdCaptor.capture(), eq(peerSsi.getBytes()),
eq(peerMatchFilter.getBytes()));
@@ -2296,88 +2423,6 @@
}
/**
- * Validate that start ranging function fills-in correct MAC addresses for peer IDs and
- * passed along to RTT module.
- */
- @Test
- public void testStartRanging() throws Exception {
- final int clientId = 1005;
- final int uid = 1000;
- final int pid = 2000;
- final String callingPackage = "com.google.somePackage";
- final byte subscribeId = 15;
- final int requestorId = 22;
- final byte[] peerMac = HexEncoding.decode("060708090A0B".toCharArray(), false);
- final String peerSsi = "some peer ssi data";
- final String peerMatchFilter = "filter binary array represented as string";
- final int rangingId = 18423;
- final RttManager.RttParams[] params = new RttManager.RttParams[2];
-
- ConfigRequest configRequest = new ConfigRequest.Builder().build();
- SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build();
-
- IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class);
- IWifiAwareDiscoverySessionCallback mockSessionCallback = mock(
- IWifiAwareDiscoverySessionCallback.class);
-
- ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class);
- ArgumentCaptor<Integer> sessionId = ArgumentCaptor.forClass(Integer.class);
- ArgumentCaptor<Integer> peerIdIdCaptor = ArgumentCaptor.forClass(Integer.class);
- ArgumentCaptor<WifiAwareClientState> clientCaptor =
- ArgumentCaptor.forClass(WifiAwareClientState.class);
- ArgumentCaptor<RttManager.RttParams[]> rttParamsCaptor =
- ArgumentCaptor.forClass(RttManager.RttParams[].class);
-
- InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mMockNative,
- mMockAwareRttStateManager);
-
- mDut.enableUsage();
- mMockLooper.dispatchAll();
- inOrder.verify(mMockNative).getCapabilities(transactionId.capture());
- mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities());
- mMockLooper.dispatchAll();
-
- // (1) connect
- mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false);
- mMockLooper.dispatchAll();
- inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(), eq(configRequest),
- eq(false), eq(true), eq(true), eq(false));
- mDut.onConfigSuccessResponse(transactionId.getValue());
- mMockLooper.dispatchAll();
- inOrder.verify(mockCallback).onConnectSuccess(clientId);
-
- // (2) subscribe & match
- mDut.subscribe(clientId, subscribeConfig, mockSessionCallback);
- mMockLooper.dispatchAll();
- inOrder.verify(mMockNative).subscribe(transactionId.capture(), eq((byte) 0),
- eq(subscribeConfig));
- mDut.onSessionConfigSuccessResponse(transactionId.getValue(), false, subscribeId);
- mDut.onMatchNotification(subscribeId, requestorId, peerMac, peerSsi.getBytes(),
- peerMatchFilter.getBytes());
- mMockLooper.dispatchAll();
- inOrder.verify(mockSessionCallback).onSessionStarted(sessionId.capture());
- inOrder.verify(mockSessionCallback).onMatch(peerIdIdCaptor.capture(),
- eq(peerSsi.getBytes()), eq(peerMatchFilter.getBytes()));
-
- // (3) start ranging: pass along a valid peer ID and an invalid one
- params[0] = new RttManager.RttParams();
- params[0].bssid = Integer.toString(peerIdIdCaptor.getValue());
- params[1] = new RttManager.RttParams();
- params[1].bssid = Integer.toString(peerIdIdCaptor.getValue() + 5);
-
- mDut.startRanging(clientId, sessionId.getValue(), params, rangingId);
- mMockLooper.dispatchAll();
- inOrder.verify(mMockAwareRttStateManager).startRanging(eq(rangingId),
- clientCaptor.capture(), rttParamsCaptor.capture());
- collector.checkThat("RttParams[0].bssid", "06:07:08:09:0a:0b",
- equalTo(rttParamsCaptor.getValue()[0].bssid));
- collector.checkThat("RttParams[1].bssid", "", equalTo(rttParamsCaptor.getValue()[1].bssid));
-
- verifyNoMoreInteractions(mockCallback, mockSessionCallback, mMockNative,
- mMockAwareRttStateManager);
- }
-
- /**
* Test sequence of configuration: (1) config1, (2) config2 - incompatible,
* (3) config3 - compatible with config1 (requiring upgrade), (4) disconnect
* config3 (should get a downgrade), (5) disconnect config1 (should get a
@@ -2765,7 +2810,7 @@
mDut.onMessageSendQueuedSuccessResponse(transactionIdConfig);
mDut.onMessageSendQueuedFailResponse(transactionIdConfig, -1);
mDut.onSessionConfigFailResponse(transactionIdConfig, false, -1);
- mDut.onMatchNotification(-1, -1, new byte[0], new byte[0], new byte[0]);
+ mDut.onMatchNotification(-1, -1, new byte[0], new byte[0], new byte[0], 0, 0);
mDut.onSessionTerminatedNotification(-1, -1, true);
mDut.onSessionTerminatedNotification(-1, -1, false);
mDut.onMessageReceivedNotification(-1, -1, new byte[0], new byte[0]);
@@ -3020,7 +3065,7 @@
ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class);
IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class);
InOrder inOrder = inOrder(mMockContext, mMockNativeManager, mMockNative, mockCallback);
- inOrder.verify(mMockNativeManager).start();
+ inOrder.verify(mMockNativeManager).start(any(Handler.class));
mDut.enableUsage();
mMockLooper.dispatchAll();
@@ -3150,13 +3195,9 @@
}
private static void installMocksInStateManager(WifiAwareStateManager awareStateManager,
- WifiAwareRttStateManager mockRtt, WifiAwareDataPathStateManager mockDpMgr)
+ WifiAwareDataPathStateManager mockDpMgr)
throws Exception {
- Field field = WifiAwareStateManager.class.getDeclaredField("mRtt");
- field.setAccessible(true);
- field.set(awareStateManager, mockRtt);
-
- field = WifiAwareStateManager.class.getDeclaredField("mDataPathMgr");
+ Field field = WifiAwareStateManager.class.getDeclaredField("mDataPathMgr");
field.setAccessible(true);
field.set(awareStateManager, mockDpMgr);
}
@@ -3256,5 +3297,17 @@
cap.maxQueuedTransmitMessages = 6;
return cap;
}
+
+ private static class Mutable<E> {
+ public E value;
+
+ Mutable() {
+ value = null;
+ }
+
+ Mutable(E value) {
+ this.value = value;
+ }
+ }
}
diff --git a/tests/wifitests/src/com/android/server/wifi/hotspot2/OsuNetworkConnectionTest.java b/tests/wifitests/src/com/android/server/wifi/hotspot2/OsuNetworkConnectionTest.java
new file mode 100644
index 0000000..c0d319f
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/hotspot2/OsuNetworkConnectionTest.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.wifi.hotspot2;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.IntentFilter;
+import android.net.Network;
+import android.net.NetworkInfo;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.net.wifi.WifiSsid;
+import android.os.Handler;
+import android.os.test.TestLooper;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.server.wifi.TestUtil;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Unit tests for {@link com.android.server.wifi.hotspot2.PasspointProvisioner}.
+ */
+@SmallTest
+public class OsuNetworkConnectionTest {
+ private static final String TAG = "OsuNetworkConnectionTest";
+ private static final int ENABLE_LOGGING = 1;
+ private static final int DISABLE_LOGGING = 0;
+
+ private static final int TEST_NETWORK_ID = 6;
+ private static final String TEST_NAI = null;
+ private static final String TEST_NAI_OSEN = "access.test.com";
+ private static final WifiSsid TEST_SSID = WifiSsid.createFromAsciiEncoded("Test SSID");
+
+ private BroadcastReceiver mBroadcastReceiver;
+ private OsuNetworkConnection mNetworkConnection;
+ private TestLooper mLooper;
+ private Handler mHandler;
+
+ @Mock Context mContext;
+ @Mock WifiManager mWifiManager;
+ @Mock OsuNetworkConnection.Callbacks mNetworkCallbacks;
+ @Mock NetworkInfo mNwInfo;
+ @Mock WifiInfo mWifiInfo;
+ @Mock Network mCurrentNetwork;
+
+ ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverCaptor = ArgumentCaptor.forClass(
+ BroadcastReceiver.class);
+ ArgumentCaptor<IntentFilter> mIntentFilterCaptor = ArgumentCaptor.forClass(
+ IntentFilter.class);
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ doReturn(mWifiManager).when(mContext)
+ .getSystemService(eq(Context.WIFI_SERVICE));
+ when(mWifiManager.isWifiEnabled()).thenReturn(true);
+ when(mWifiManager.enableNetwork(TEST_NETWORK_ID, true)).thenReturn(true);
+ when(mWifiManager.addNetwork(any(WifiConfiguration.class))).thenReturn(TEST_NETWORK_ID);
+ when(mWifiManager.getCurrentNetwork()).thenReturn(mCurrentNetwork);
+ when(mWifiInfo.getNetworkId()).thenReturn(TEST_NETWORK_ID);
+ mLooper = new TestLooper();
+ mHandler = new Handler(mLooper.getLooper());
+ mNetworkConnection = new OsuNetworkConnection(mContext);
+ mNetworkConnection.enableVerboseLogging(ENABLE_LOGGING);
+ }
+
+ /**
+ * Verify that the class registers for receiving the necessary broadcast intents upon init.
+ * Verify that the initialization only occurs once even if init() is called multiple times.
+ */
+ @Test
+ public void verifyBroadcastIntentRegistration() {
+ mNetworkConnection.init(mHandler);
+ verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(),
+ mIntentFilterCaptor.capture(), any(), eq(mHandler));
+ verify(mWifiManager).isWifiEnabled();
+ mLooper.dispatchAll();
+ IntentFilter intentFilter = mIntentFilterCaptor.getValue();
+ assertEquals(intentFilter.countActions(), 2);
+ }
+
+ /**
+ * Verifies that onWifiEnabled() callback is invoked when the relevant intent is
+ * received and the caller is subscribed to receive the callback.
+ */
+ @Test
+ public void verifyWifiStateCallbacks() {
+ when(mWifiManager.isWifiEnabled()).thenReturn(false);
+ mNetworkConnection.init(mHandler);
+ verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(),
+ any(IntentFilter.class), any(), eq(mHandler));
+ mBroadcastReceiver = mBroadcastReceiverCaptor.getValue();
+ mLooper.dispatchAll();
+ mNetworkConnection.setEventCallback(mNetworkCallbacks);
+ TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext,
+ WifiManager.WIFI_STATE_ENABLED);
+ TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext,
+ WifiManager.WIFI_STATE_DISABLED);
+ mNetworkConnection.setEventCallback(null);
+ TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext,
+ WifiManager.WIFI_STATE_ENABLED);
+ TestUtil.sendWifiStateChanged(mBroadcastReceiver, mContext,
+ WifiManager.WIFI_STATE_DISABLED);
+ verify(mNetworkCallbacks, times(1)).onWifiEnabled();
+ verify(mNetworkCallbacks, times(1)).onWifiDisabled();
+ }
+
+ /**
+ * Verifies that connect() API returns false when Wifi is not enabled
+ */
+ @Test
+ public void verifyNetworkConnectionWhenWifiIsDisabled() {
+ when(mWifiManager.isWifiEnabled()).thenReturn(false);
+ mNetworkConnection.init(mHandler);
+ assertEquals(false, mNetworkConnection.connect(TEST_SSID, TEST_NAI));
+ }
+
+ /**
+ * Verifies that connect() API returns false when OSU AP is a part of an OSEN
+ */
+ @Test
+ public void verifyOSENUnsupported() {
+ mNetworkConnection.init(mHandler);
+ assertEquals(false, mNetworkConnection.connect(TEST_SSID, TEST_NAI_OSEN));
+ }
+
+ /**
+ * Verifies that connect() API returns false when WifiManager's addNetwork()
+ * returns an invalid network ID
+ */
+ @Test
+ public void verifyNetworkConnectionWhenAddNetworkFails() {
+ when(mWifiManager.addNetwork(any(WifiConfiguration.class))).thenReturn(-1);
+ mNetworkConnection.init(mHandler);
+ assertEquals(false, mNetworkConnection.connect(TEST_SSID, TEST_NAI));
+ }
+
+ /**
+ * Verifies that connect() API returns false when WifiManager's enableNetwork()
+ * fails for the given network ID corresponding to the OSU AP
+ */
+ @Test
+ public void verifyNetworkConnectionWhenEnableNetworkFails() {
+ when(mWifiManager.enableNetwork(TEST_NETWORK_ID, true)).thenReturn(false);
+ mNetworkConnection.init(mHandler);
+ assertEquals(false, mNetworkConnection.connect(TEST_SSID, TEST_NAI));
+ verify(mWifiManager).removeNetwork(TEST_NETWORK_ID);
+ }
+
+ /**
+ * Verifies that network state callbacks are invoked when the NETWORK_STATE_CHANGED intent
+ * is received and when WifiManager has successfully requested connection to the OSU AP.
+ */
+ @Test
+ public void verifyNetworkCallbackInvokedWhenRegistered() {
+ mNetworkConnection.init(mHandler);
+ verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(),
+ any(IntentFilter.class), any(), eq(mHandler));
+ mBroadcastReceiver = mBroadcastReceiverCaptor.getValue();
+
+ mNetworkConnection.setEventCallback(mNetworkCallbacks);
+ assertEquals(true, mNetworkConnection.connect(TEST_SSID, TEST_NAI));
+ mLooper.dispatchAll();
+
+ when(mNwInfo.getDetailedState()).thenReturn(NetworkInfo.DetailedState.CONNECTED);
+ TestUtil.sendNetworkStateChanged(mBroadcastReceiver, mContext,
+ mNwInfo, mWifiInfo);
+ verify(mNetworkCallbacks).onConnected(mCurrentNetwork);
+
+ when(mNwInfo.getDetailedState()).thenReturn(NetworkInfo.DetailedState.DISCONNECTED);
+ TestUtil.sendNetworkStateChanged(mBroadcastReceiver, mContext, mNwInfo, mWifiInfo);
+ verify(mNetworkCallbacks).onDisconnected();
+ verify(mWifiManager).removeNetwork(TEST_NETWORK_ID);
+ }
+
+ /**
+ * Verifies that the onConnected() callback is not invoked when the Network State Changed
+ * intent is called when WifiManager has successfully connected to a network that's not the
+ * OSU AP.
+ */
+ @Test
+ public void verifyNetworkDisconnectedCallbackConnectedToAnotherNetwork() {
+ when(mWifiInfo.getNetworkId()).thenReturn(TEST_NETWORK_ID + 1);
+ when(mNwInfo.getDetailedState()).thenReturn(NetworkInfo.DetailedState.CONNECTED);
+ mNetworkConnection.init(mHandler);
+ verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(),
+ any(IntentFilter.class), any(), eq(mHandler));
+ mLooper.dispatchAll();
+
+ mBroadcastReceiver = mBroadcastReceiverCaptor.getValue();
+ mNetworkConnection.setEventCallback(mNetworkCallbacks);
+ assertEquals(true, mNetworkConnection.connect(TEST_SSID, TEST_NAI));
+ TestUtil.sendNetworkStateChanged(mBroadcastReceiver, mContext,
+ mNwInfo, mWifiInfo);
+ verify(mNetworkCallbacks, never()).onConnected(any(Network.class));
+ verify(mWifiManager).removeNetwork(TEST_NETWORK_ID);
+ }
+
+ /**
+ * Verifies that WifiManager's removeNetwork() is called when disconnectIfNeeded() is called
+ * on the OSU AP's network ID.
+ */
+ @Test
+ public void verifyNetworkTearDown() {
+ mNetworkConnection.init(mHandler);
+ assertEquals(true, mNetworkConnection.connect(TEST_SSID, TEST_NAI));
+ mNetworkConnection.disconnectIfNeeded();
+ verify(mWifiManager).removeNetwork(TEST_NETWORK_ID);
+ }
+}
+
diff --git a/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java b/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java
index 01566c2..e0e6df1 100644
--- a/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java
@@ -33,6 +33,7 @@
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.anyLong;
import static org.mockito.Mockito.anyMap;
import static org.mockito.Mockito.doThrow;
@@ -52,12 +53,16 @@
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiEnterpriseConfig;
+import android.net.wifi.WifiManager;
import android.net.wifi.WifiSsid;
+import android.net.wifi.hotspot2.IProvisioningCallback;
import android.net.wifi.hotspot2.OsuProvider;
import android.net.wifi.hotspot2.PasspointConfiguration;
import android.net.wifi.hotspot2.pps.Credential;
import android.net.wifi.hotspot2.pps.HomeSp;
+import android.os.Looper;
import android.os.UserHandle;
+import android.os.test.TestLooper;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Base64;
import android.util.Pair;
@@ -101,7 +106,7 @@
public class PasspointManagerTest {
private static final long BSSID = 0x112233445566L;
private static final String ICON_FILENAME = "test";
- private static final String TEST_FQDN = "test1.test.com";
+ private static final String TEST_FQDN = "test1.test.com";
private static final String TEST_FRIENDLY_NAME = "friendly name";
private static final String TEST_REALM = "realm.test.com";
private static final String TEST_IMSI = "1234*";
@@ -115,6 +120,7 @@
private static final ANQPNetworkKey TEST_ANQP_KEY = ANQPNetworkKey.buildKey(
TEST_SSID, TEST_BSSID, TEST_HESSID, TEST_ANQP_DOMAIN_ID);
private static final int TEST_CREATOR_UID = 1234;
+ private static final int TEST_UID = 1500;
@Mock Context mContext;
@Mock WifiNative mWifiNative;
@@ -130,6 +136,11 @@
@Mock WifiConfigStore mWifiConfigStore;
@Mock PasspointConfigStoreData.DataSource mDataSource;
@Mock WifiMetrics mWifiMetrics;
+ @Mock OsuNetworkConnection mOsuNetworkConnection;
+ @Mock PasspointProvisioner mPasspointProvisioner;
+ @Mock IProvisioningCallback mCallback;
+
+ TestLooper mLooper;
PasspointManager mManager;
/** Sets up test. */
@@ -140,6 +151,10 @@
when(mObjectFactory.makeANQPRequestManager(any(), eq(mClock)))
.thenReturn(mAnqpRequestManager);
when(mObjectFactory.makeCertificateVerifier()).thenReturn(mCertVerifier);
+ when(mObjectFactory.makeOsuNetworkConnection(any(Context.class)))
+ .thenReturn(mOsuNetworkConnection);
+ when(mObjectFactory.makePasspointProvisioner(any(Context.class),
+ any(OsuNetworkConnection.class))).thenReturn(mPasspointProvisioner);
mManager = new PasspointManager(mContext, mWifiNative, mWifiKeyStore, mClock,
mSimAccessor, mObjectFactory, mWifiConfigManager, mWifiConfigStore, mWifiMetrics);
ArgumentCaptor<PasspointEventHandler.Callbacks> callbacks =
@@ -152,6 +167,7 @@
any(WifiKeyStore.class), any(SIMAccessor.class), dataSource.capture());
mCallbacks = callbacks.getValue();
mDataSource = dataSource.getValue();
+ mLooper = new TestLooper();
}
/**
@@ -208,10 +224,10 @@
*
* @return {@link PasspointConfiguration}
*/
- private PasspointConfiguration createTestConfigWithUserCredential() {
+ private PasspointConfiguration createTestConfigWithUserCredential(String fqdn) {
PasspointConfiguration config = new PasspointConfiguration();
HomeSp homeSp = new HomeSp();
- homeSp.setFqdn(TEST_FQDN);
+ homeSp.setFqdn(fqdn);
homeSp.setFriendlyName(TEST_FRIENDLY_NAME);
config.setHomeSp(homeSp);
Credential credential = new Credential();
@@ -254,8 +270,8 @@
*
* @return {@link PasspointProvider}
*/
- private PasspointProvider addTestProvider() {
- PasspointConfiguration config = createTestConfigWithUserCredential();
+ private PasspointProvider addTestProvider(String fqdn) {
+ PasspointConfiguration config = createTestConfigWithUserCredential(fqdn);
PasspointProvider provider = createMockProvider(config);
when(mObjectFactory.makePasspointProvider(eq(config), eq(mWifiKeyStore),
eq(mSimAccessor), anyLong(), eq(TEST_CREATOR_UID))).thenReturn(provider);
@@ -437,7 +453,7 @@
*/
@Test
public void addProviderWithInvalidCredential() throws Exception {
- PasspointConfiguration config = createTestConfigWithUserCredential();
+ PasspointConfiguration config = createTestConfigWithUserCredential(TEST_FQDN);
// EAP-TLS not allowed for user credential.
config.getCredential().getUserCredential().setEapType(EAPConstants.EAP_TLS);
assertFalse(mManager.addOrUpdateProvider(config, TEST_CREATOR_UID));
@@ -452,7 +468,7 @@
*/
@Test
public void addRemoveProviderWithValidUserCredential() throws Exception {
- PasspointConfiguration config = createTestConfigWithUserCredential();
+ PasspointConfiguration config = createTestConfigWithUserCredential(TEST_FQDN);
PasspointProvider provider = createMockProvider(config);
when(mObjectFactory.makePasspointProvider(eq(config), eq(mWifiKeyStore),
eq(mSimAccessor), anyLong(), eq(TEST_CREATOR_UID))).thenReturn(provider);
@@ -555,7 +571,7 @@
// Add another provider with the same base domain as the existing provider.
// This should replace the existing provider with the new configuration.
- PasspointConfiguration newConfig = createTestConfigWithUserCredential();
+ PasspointConfiguration newConfig = createTestConfigWithUserCredential(TEST_FQDN);
PasspointProvider newProvider = createMockProvider(newConfig);
when(mObjectFactory.makePasspointProvider(eq(newConfig), eq(mWifiKeyStore),
eq(mSimAccessor), anyLong(), eq(TEST_CREATOR_UID))).thenReturn(newProvider);
@@ -580,7 +596,7 @@
*/
@Test
public void addProviderOnKeyInstallationFailiure() throws Exception {
- PasspointConfiguration config = createTestConfigWithUserCredential();
+ PasspointConfiguration config = createTestConfigWithUserCredential(TEST_FQDN);
PasspointProvider provider = mock(PasspointProvider.class);
when(provider.installCertsAndKeys()).thenReturn(false);
when(mObjectFactory.makePasspointProvider(eq(config), eq(mWifiKeyStore),
@@ -597,7 +613,7 @@
*/
@Test
public void addProviderWithInvalidCaCert() throws Exception {
- PasspointConfiguration config = createTestConfigWithUserCredential();
+ PasspointConfiguration config = createTestConfigWithUserCredential(TEST_FQDN);
doThrow(new GeneralSecurityException())
.when(mCertVerifier).verifyCaCert(any(X509Certificate.class));
assertFalse(mManager.addOrUpdateProvider(config, TEST_CREATOR_UID));
@@ -613,7 +629,7 @@
*/
@Test
public void addProviderWithR2Config() throws Exception {
- PasspointConfiguration config = createTestConfigWithUserCredential();
+ PasspointConfiguration config = createTestConfigWithUserCredential(TEST_FQDN);
config.setUpdateIdentifier(1);
PasspointProvider provider = createMockProvider(config);
when(mObjectFactory.makePasspointProvider(eq(config), eq(mWifiKeyStore),
@@ -654,7 +670,7 @@
*/
@Test
public void matchProviderWithAnqpCacheMissed() throws Exception {
- addTestProvider();
+ addTestProvider(TEST_FQDN);
when(mAnqpCache.getEntry(TEST_ANQP_KEY)).thenReturn(null);
assertNull(mManager.matchProvider(createTestScanResult()));
@@ -670,7 +686,7 @@
*/
@Test
public void matchProviderAsHomeProvider() throws Exception {
- PasspointProvider provider = addTestProvider();
+ PasspointProvider provider = addTestProvider(TEST_FQDN);
ANQPData entry = new ANQPData(mClock, null);
when(mAnqpCache.getEntry(TEST_ANQP_KEY)).thenReturn(entry);
@@ -688,7 +704,7 @@
*/
@Test
public void matchProviderAsRoamingProvider() throws Exception {
- PasspointProvider provider = addTestProvider();
+ PasspointProvider provider = addTestProvider(TEST_FQDN);
ANQPData entry = new ANQPData(mClock, null);
when(mAnqpCache.getEntry(TEST_ANQP_KEY)).thenReturn(entry);
@@ -706,7 +722,7 @@
*/
@Test
public void matchProviderWithNoMatch() throws Exception {
- PasspointProvider provider = addTestProvider();
+ PasspointProvider provider = addTestProvider(TEST_FQDN);
ANQPData entry = new ANQPData(mClock, null);
when(mAnqpCache.getEntry(TEST_ANQP_KEY)).thenReturn(entry);
@@ -761,7 +777,7 @@
*/
@Test
public void getMatchingWifiConfigForHomeProviderAP() throws Exception {
- PasspointProvider provider = addTestProvider();
+ PasspointProvider provider = addTestProvider(TEST_FQDN);
ANQPData entry = new ANQPData(mClock, null);
when(mAnqpCache.getEntry(TEST_ANQP_KEY)).thenReturn(entry);
@@ -780,7 +796,7 @@
*/
@Test
public void getMatchingWifiConfigForRoamingProviderAP() throws Exception {
- PasspointProvider provider = addTestProvider();
+ PasspointProvider provider = addTestProvider(TEST_FQDN);
ANQPData entry = new ANQPData(mClock, null);
when(mAnqpCache.getEntry(TEST_ANQP_KEY)).thenReturn(entry);
@@ -799,7 +815,7 @@
*/
@Test
public void getMatchingWifiConfigWithNoMatchingProvider() throws Exception {
- PasspointProvider provider = addTestProvider();
+ PasspointProvider provider = addTestProvider(TEST_FQDN);
ANQPData entry = new ANQPData(mClock, null);
when(mAnqpCache.getEntry(TEST_ANQP_KEY)).thenReturn(entry);
@@ -859,6 +875,97 @@
}
/**
+ * Verify that an expected set of {@link WifiConfiguration} will be returned when a
+ * {@link ScanResult} is matched to a provider.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void getAllMatchingWifiConfigsForProviderAP() throws Exception {
+ PasspointProvider providerHome = addTestProvider(TEST_FQDN + 0);
+ PasspointProvider providerRoaming = addTestProvider(TEST_FQDN + 1);
+ PasspointProvider providerNone = addTestProvider(TEST_FQDN + 2);
+ ANQPData entry = new ANQPData(mClock, null);
+
+ when(mAnqpCache.getEntry(TEST_ANQP_KEY)).thenReturn(entry);
+
+ when(providerHome.match(anyMap())).thenReturn(PasspointMatch.HomeProvider);
+ when(providerRoaming.match(anyMap())).thenReturn(PasspointMatch.RoamingProvider);
+ when(providerNone.match(anyMap())).thenReturn(PasspointMatch.None);
+
+ when(providerHome.getWifiConfig()).thenReturn(new WifiConfiguration());
+ when(providerRoaming.getWifiConfig()).thenReturn(new WifiConfiguration());
+ when(providerNone.getWifiConfig()).thenReturn(new WifiConfiguration());
+
+ List<WifiConfiguration> configs = mManager.getAllMatchingWifiConfigs(
+ createTestScanResult());
+
+ assertEquals(2, configs.size());
+ int observedHome = 0;
+ int observedRoaming = 0;
+ for (WifiConfiguration config : configs) {
+ assertEquals(ScanResultUtil.createQuotedSSID(TEST_SSID), config.SSID);
+ if (config.isHomeProviderNetwork) {
+ observedHome++;
+ } else {
+ observedRoaming++;
+ }
+ }
+ assertEquals(1, observedHome);
+ assertEquals(1, observedRoaming);
+ }
+
+ /**
+ * Verify that an empty list will be returned when trying to get all matching
+ * {@link WifiConfiguration} for a {@code null} {@link ScanResult}.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void getAllMatchingWifiConfigsWithNullScanResult() throws Exception {
+ assertEquals(0, mManager.getAllMatchingWifiConfigs(null).size());
+ }
+
+ /**
+ * Verify that an empty list will be returned when trying to get a all matching
+ * {@link WifiConfiguration} for a {@link ScanResult} with a {@code null} BSSID.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void getAllMatchingWifiConfigWithNullBSSID() throws Exception {
+ ScanResult scanResult = createTestScanResult();
+ scanResult.BSSID = null;
+ assertEquals(0, mManager.getAllMatchingWifiConfigs(scanResult).size());
+ }
+
+ /**
+ * Verify that an empty list will be returned when trying to get all matching
+ * {@link WifiConfiguration} for a {@link ScanResult} with an invalid BSSID.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void getAllMatchingWifiConfigWithInvalidBSSID() throws Exception {
+ ScanResult scanResult = createTestScanResult();
+ scanResult.BSSID = "asdfdasfas";
+ assertEquals(0, mManager.getAllMatchingWifiConfigs(scanResult).size());
+ }
+
+ /**
+ * Verify that an empty list will be returned when trying to get all matching
+ * {@link WifiConfiguration} for a non-Passpoint AP.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void getAllMatchingWifiConfigForNonPasspointAP() throws Exception {
+ ScanResult scanResult = createTestScanResult();
+ scanResult.flags = 0;
+ assertEquals(0, mManager.getAllMatchingWifiConfigs(scanResult).size());
+ }
+
+ /**
* Verify that an empty list will be returned when retrieving OSU providers for an AP with
* null scan result.
*
@@ -954,7 +1061,7 @@
@Test
public void verifyProvidersAfterDataSourceUpdate() throws Exception {
// Update the provider list in the data source.
- PasspointConfiguration config = createTestConfigWithUserCredential();
+ PasspointConfiguration config = createTestConfigWithUserCredential(TEST_FQDN);
PasspointProvider provider = createMockProvider(config);
List<PasspointProvider> providers = new ArrayList<>();
providers.add(provider);
@@ -978,7 +1085,7 @@
assertEquals(providerIndex, mDataSource.getProviderIndex());
// Add a provider.
- PasspointConfiguration config = createTestConfigWithUserCredential();
+ PasspointConfiguration config = createTestConfigWithUserCredential(TEST_FQDN);
PasspointProvider provider = createMockProvider(config);
// Verify the provider ID used to create the new provider.
when(mObjectFactory.makePasspointProvider(eq(config), eq(mWifiKeyStore),
@@ -1225,7 +1332,7 @@
*/
@Test
public void providerNetworkConnectedFirstTime() throws Exception {
- PasspointProvider provider = addTestProvider();
+ PasspointProvider provider = addTestProvider(TEST_FQDN);
when(provider.getHasEverConnected()).thenReturn(false);
mManager.onPasspointNetworkConnected(TEST_FQDN);
verify(provider).setHasEverConnected(eq(true));
@@ -1240,7 +1347,7 @@
*/
@Test
public void providerNetworkConnectedNotFirstTime() throws Exception {
- PasspointProvider provider = addTestProvider();
+ PasspointProvider provider = addTestProvider(TEST_FQDN);
when(provider.getHasEverConnected()).thenReturn(true);
mManager.onPasspointNetworkConnected(TEST_FQDN);
verify(provider, never()).setHasEverConnected(anyBoolean());
@@ -1254,7 +1361,7 @@
*/
@Test
public void updateMetrics() throws Exception {
- PasspointProvider provider = addTestProvider();
+ PasspointProvider provider = addTestProvider(TEST_FQDN);
// Provider have not provided a successful network connection.
int expectedInstalledProviders = 1;
@@ -1273,4 +1380,18 @@
verify(mWifiMetrics).updateSavedPasspointProfiles(
eq(expectedInstalledProviders), eq(expectedConnectedProviders));
}
+ /**
+ * Verify Passpoint Manager's provisioning APIs by invoking methods in PasspointProvisioner for
+ * initiailization and provisioning a provider.
+ */
+ @Test
+ public void verifyPasspointProvisioner() {
+ mManager.initializeProvisioner(mLooper.getLooper());
+ verify(mPasspointProvisioner).init(any(Looper.class));
+ when(mPasspointProvisioner.startSubscriptionProvisioning(anyInt(), any(OsuProvider.class),
+ any(IProvisioningCallback.class))).thenReturn(true);
+ OsuProvider osuProvider = PasspointProvisioningTestUtil.generateOsuProvider(true);
+ assertEquals(true,
+ mManager.startSubscriptionProvisioning(TEST_UID, osuProvider, mCallback));
+ }
}
diff --git a/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointProvisionerTest.java b/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointProvisionerTest.java
new file mode 100644
index 0000000..4583531
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointProvisionerTest.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wifi.hotspot2;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.net.wifi.WifiManager;
+import android.net.wifi.hotspot2.IProvisioningCallback;
+import android.net.wifi.hotspot2.OsuProvider;
+import android.os.test.TestLooper;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Unit tests for {@link com.android.server.wifi.hotspot2.PasspointProvisioner}.
+ */
+@SmallTest
+public class PasspointProvisionerTest {
+ private static final String TAG = "PasspointProvisionerTest";
+
+ private static final int TEST_UID = 1500;
+
+ private PasspointProvisioner mPasspointProvisioner;
+ private TestLooper mLooper = new TestLooper();
+
+ @Mock Context mContext;
+ @Mock WifiManager mWifiManager;
+ @Mock IProvisioningCallback mCallback;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ when(mWifiManager.isWifiEnabled()).thenReturn(true);
+ doReturn(mWifiManager).when(mContext)
+ .getSystemService(eq(Context.WIFI_SERVICE));
+ OsuNetworkConnection osuNetworkConnection = new OsuNetworkConnection(mContext);
+ mPasspointProvisioner = new PasspointProvisioner(mContext, osuNetworkConnection);
+ }
+
+ /**
+ * Verifies that initialization is required before starting subscription
+ * provisioning with a provider
+ */
+ @Test
+ public void verifyInitBeforeStartProvisioning() {
+ OsuProvider osuProvider = PasspointProvisioningTestUtil.generateOsuProvider(true);
+ mPasspointProvisioner.init(mLooper.getLooper());
+ assertTrue(mPasspointProvisioner.startSubscriptionProvisioning(
+ TEST_UID, osuProvider, mCallback));
+ }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/rtt/RttNativeTest.java b/tests/wifitests/src/com/android/server/wifi/rtt/RttNativeTest.java
new file mode 100644
index 0000000..51fed83
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/rtt/RttNativeTest.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package com.android.server.wifi.rtt;
+
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.hardware.wifi.V1_0.IWifiRttController;
+import android.hardware.wifi.V1_0.RttConfig;
+import android.hardware.wifi.V1_0.RttPeerType;
+import android.hardware.wifi.V1_0.RttResult;
+import android.hardware.wifi.V1_0.RttStatus;
+import android.hardware.wifi.V1_0.RttType;
+import android.hardware.wifi.V1_0.WifiStatus;
+import android.hardware.wifi.V1_0.WifiStatusCode;
+import android.net.wifi.rtt.RangingRequest;
+
+import com.android.server.wifi.HalDeviceManager;
+
+import libcore.util.HexEncoding;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ErrorCollector;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Unit test harness for the RttNative class.
+ */
+public class RttNativeTest {
+ private RttNative mDut;
+
+ private ArgumentCaptor<ArrayList> mRttConfigCaptor = ArgumentCaptor.forClass(ArrayList.class);
+ private ArgumentCaptor<List> mRttResultCaptor = ArgumentCaptor.forClass(List.class);
+ private ArgumentCaptor<HalDeviceManager.ManagerStatusListener> mHdmStatusListener =
+ ArgumentCaptor.forClass(HalDeviceManager.ManagerStatusListener.class);
+
+ @Rule
+ public ErrorCollector collector = new ErrorCollector();
+
+ @Mock
+ public RttServiceImpl mockRttServiceImpl;
+
+ @Mock
+ public HalDeviceManager mockHalDeviceManager;
+
+ @Mock
+ public IWifiRttController mockRttController;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ when(mockHalDeviceManager.isStarted()).thenReturn(true);
+ when(mockHalDeviceManager.createRttController()).thenReturn(mockRttController);
+
+ WifiStatus status = new WifiStatus();
+ status.code = WifiStatusCode.SUCCESS;
+ when(mockRttController.registerEventCallback(any())).thenReturn(status);
+ when(mockRttController.rangeRequest(anyInt(), any(ArrayList.class))).thenReturn(status);
+ when(mockRttController.rangeCancel(anyInt(), any(ArrayList.class))).thenReturn(status);
+
+ mDut = new RttNative(mockRttServiceImpl, mockHalDeviceManager);
+ mDut.start();
+ verify(mockHalDeviceManager).registerStatusListener(mHdmStatusListener.capture(), any());
+ verify(mockRttController).registerEventCallback(any());
+ verify(mockRttServiceImpl).enable();
+ assertTrue(mDut.isReady());
+ }
+
+ /**
+ * Validate successful ranging flow.
+ */
+ @Test
+ public void testRangeRequest() throws Exception {
+ int cmdId = 55;
+ RangingRequest request = RttTestUtils.getDummyRangingRequest((byte) 0);
+
+ // (1) issue range request
+ mDut.rangeRequest(cmdId, request);
+
+ // (2) verify HAL call and parameters
+ verify(mockRttController).rangeRequest(eq(cmdId), mRttConfigCaptor.capture());
+
+ // verify contents of HAL request (hard codes knowledge from getDummyRangingRequest()).
+ ArrayList<RttConfig> halRequest = mRttConfigCaptor.getValue();
+
+ collector.checkThat("number of entries", halRequest.size(),
+ equalTo(request.mRttPeers.size()));
+
+ RttConfig rttConfig = halRequest.get(0);
+ collector.checkThat("entry 0: MAC", rttConfig.addr,
+ equalTo(HexEncoding.decode("000102030400".toCharArray(), false)));
+ collector.checkThat("entry 0: MAC", rttConfig.type, equalTo(RttType.TWO_SIDED));
+ collector.checkThat("entry 0: MAC", rttConfig.peer, equalTo(RttPeerType.AP));
+
+ rttConfig = halRequest.get(1);
+ collector.checkThat("entry 1: MAC", rttConfig.addr,
+ equalTo(HexEncoding.decode("0A0B0C0D0E00".toCharArray(), false)));
+ collector.checkThat("entry 1: MAC", rttConfig.type, equalTo(RttType.ONE_SIDED));
+ collector.checkThat("entry 1: MAC", rttConfig.peer, equalTo(RttPeerType.AP));
+
+ rttConfig = halRequest.get(2);
+ collector.checkThat("entry 2: MAC", rttConfig.addr,
+ equalTo(HexEncoding.decode("080908070605".toCharArray(), false)));
+ collector.checkThat("entry 2: MAC", rttConfig.type, equalTo(RttType.TWO_SIDED));
+ collector.checkThat("entry 2: MAC", rttConfig.peer, equalTo(RttPeerType.NAN));
+
+ verifyNoMoreInteractions(mockRttController);
+ }
+
+ /**
+ * Validate no range request when Wi-Fi is down
+ */
+ @Test
+ public void testWifiDown() throws Exception {
+ int cmdId = 55;
+ RangingRequest request = RttTestUtils.getDummyRangingRequest((byte) 0);
+
+ // (1) configure Wi-Fi down and send a status change indication
+ when(mockHalDeviceManager.isStarted()).thenReturn(false);
+ mHdmStatusListener.getValue().onStatusChanged();
+ verify(mockRttServiceImpl).disable();
+ assertFalse(mDut.isReady());
+
+ // (2) issue range request
+ mDut.rangeRequest(cmdId, request);
+
+ verifyNoMoreInteractions(mockRttServiceImpl, mockRttController);
+ }
+
+ /**
+ * Validate ranging cancel flow.
+ */
+ @Test
+ public void testRangeCancel() throws Exception {
+ int cmdId = 66;
+ ArrayList<byte[]> macAddresses = new ArrayList<>();
+ byte[] mac1 = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
+ byte[] mac2 = { 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
+ macAddresses.add(mac1);
+ macAddresses.add(mac2);
+
+ // (1) issue cancel request
+ mDut.rangeCancel(cmdId, macAddresses);
+
+ // (2) verify HAL call and parameters
+ verify(mockRttController).rangeCancel(cmdId, macAddresses);
+
+ verifyNoMoreInteractions(mockRttController);
+ }
+
+ /**
+ * Validate correct result conversion from HAL to framework.
+ */
+ @Test
+ public void testRangeResults() throws Exception {
+ int cmdId = 55;
+ ArrayList<RttResult> results = new ArrayList<>();
+ RttResult res = new RttResult();
+ res.addr[0] = 5;
+ res.addr[1] = 6;
+ res.addr[2] = 7;
+ res.addr[3] = 8;
+ res.addr[4] = 9;
+ res.addr[5] = 10;
+ res.status = RttStatus.SUCCESS;
+ res.distanceInMm = 1500;
+ res.timeStampInUs = 666;
+ results.add(res);
+
+ // (1) have HAL call native with results
+ mDut.onResults(cmdId, results);
+
+ // (2) verify call to framework
+ verify(mockRttServiceImpl).onRangingResults(eq(cmdId), mRttResultCaptor.capture());
+
+ // verify contents of the framework results
+ List<RttResult> rttR = mRttResultCaptor.getValue();
+
+ collector.checkThat("number of entries", rttR.size(), equalTo(1));
+
+ RttResult rttResult = rttR.get(0);
+ collector.checkThat("status", rttResult.status,
+ equalTo(RttStatus.SUCCESS));
+ collector.checkThat("mac", rttResult.addr,
+ equalTo(HexEncoding.decode("05060708090A".toCharArray(), false)));
+ collector.checkThat("distanceCm", rttResult.distanceInMm, equalTo(1500));
+ collector.checkThat("timestamp", rttResult.timeStampInUs, equalTo(666L));
+
+ verifyNoMoreInteractions(mockRttController);
+ }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/rtt/RttServiceImplTest.java b/tests/wifitests/src/com/android/server/wifi/rtt/RttServiceImplTest.java
new file mode 100644
index 0000000..ee8c15f
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/rtt/RttServiceImplTest.java
@@ -0,0 +1,1158 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package com.android.server.wifi.rtt;
+
+import static com.android.server.wifi.rtt.RttTestUtils.compareListContentsNoOrdering;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManager;
+import android.app.AlarmManager;
+import android.app.test.MockAnswerUtil;
+import android.app.test.TestAlarmManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.hardware.wifi.V1_0.RttResult;
+import android.net.wifi.aware.IWifiAwareMacAddressProvider;
+import android.net.wifi.aware.IWifiAwareManager;
+import android.net.wifi.aware.PeerHandle;
+import android.net.wifi.rtt.IRttCallback;
+import android.net.wifi.rtt.RangingRequest;
+import android.net.wifi.rtt.RangingResult;
+import android.net.wifi.rtt.RangingResultCallback;
+import android.net.wifi.rtt.ResponderConfig;
+import android.net.wifi.rtt.WifiRttManager;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.IPowerManager;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.WorkSource;
+import android.os.test.TestLooper;
+import android.util.Pair;
+
+import com.android.server.wifi.Clock;
+import com.android.server.wifi.util.WifiPermissionsUtil;
+
+import libcore.util.HexEncoding;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Unit test harness for the RttServiceImpl class.
+ */
+public class RttServiceImplTest {
+ private RttServiceImplSpy mDut;
+ private TestLooper mMockLooper;
+ private TestAlarmManager mAlarmManager;
+ private PowerManager mMockPowerManager;
+ private BroadcastReceiver mPowerBcastReceiver;
+
+ private final String mPackageName = "some.package.name.for.rtt.app";
+ private int mDefaultUid = 1500;
+
+ private ArgumentCaptor<Integer> mIntCaptor = ArgumentCaptor.forClass(Integer.class);
+ private ArgumentCaptor<IBinder.DeathRecipient> mDeathRecipientCaptor = ArgumentCaptor
+ .forClass(IBinder.DeathRecipient.class);
+ private ArgumentCaptor<RangingRequest> mRequestCaptor = ArgumentCaptor.forClass(
+ RangingRequest.class);
+ private ArgumentCaptor<List> mListCaptor = ArgumentCaptor.forClass(List.class);
+
+ private BinderLinkToDeathAnswer mBinderLinkToDeathCounter = new BinderLinkToDeathAnswer();
+ private BinderUnlinkToDeathAnswer mBinderUnlinkToDeathCounter = new BinderUnlinkToDeathAnswer();
+
+ private InOrder mInOrder;
+
+ @Mock
+ public Context mockContext;
+
+ @Mock
+ public ActivityManager mockActivityManager;
+
+ @Mock
+ public Clock mockClock;
+
+ @Mock
+ public RttNative mockNative;
+
+ @Mock
+ public IWifiAwareManager mockAwareManagerBinder;
+
+ @Mock
+ public WifiPermissionsUtil mockPermissionUtil;
+
+ @Mock
+ public IBinder mockIbinder;
+
+ @Mock
+ public IRttCallback mockCallback;
+
+ /**
+ * Using instead of spy to avoid native crash failures - possibly due to
+ * spy's copying of state.
+ */
+ private class RttServiceImplSpy extends RttServiceImpl {
+ public int fakeUid;
+
+ RttServiceImplSpy(Context context) {
+ super(context);
+ }
+
+ /**
+ * Return the fake UID instead of the real one: pseudo-spy
+ * implementation.
+ */
+ @Override
+ public int getMockableCallingUid() {
+ return fakeUid;
+ }
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ mDut = new RttServiceImplSpy(mockContext);
+ mDut.fakeUid = mDefaultUid;
+ mMockLooper = new TestLooper();
+
+ mAlarmManager = new TestAlarmManager();
+ when(mockContext.getSystemService(Context.ALARM_SERVICE))
+ .thenReturn(mAlarmManager.getAlarmManager());
+ mInOrder = inOrder(mAlarmManager.getAlarmManager(), mockContext);
+
+ when(mockContext.getSystemService(Context.ACTIVITY_SERVICE)).thenReturn(
+ mockActivityManager);
+ when(mockActivityManager.getUidImportance(anyInt())).thenReturn(
+ ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE);
+
+ when(mockPermissionUtil.checkCallersLocationPermission(eq(mPackageName),
+ anyInt())).thenReturn(true);
+ when(mockNative.isReady()).thenReturn(true);
+ when(mockNative.rangeRequest(anyInt(), any(RangingRequest.class))).thenReturn(true);
+
+ mMockPowerManager = new PowerManager(mockContext, mock(IPowerManager.class),
+ new Handler(mMockLooper.getLooper()));
+ when(mMockPowerManager.isDeviceIdleMode()).thenReturn(false);
+ when(mockContext.getSystemServiceName(PowerManager.class)).thenReturn(
+ Context.POWER_SERVICE);
+ when(mockContext.getSystemService(PowerManager.class)).thenReturn(mMockPowerManager);
+
+ doAnswer(mBinderLinkToDeathCounter).when(mockIbinder).linkToDeath(any(), anyInt());
+ doAnswer(mBinderUnlinkToDeathCounter).when(mockIbinder).unlinkToDeath(any(), anyInt());
+
+ mDut.start(mMockLooper.getLooper(), mockClock, mockAwareManagerBinder, mockNative,
+ mockPermissionUtil);
+ mMockLooper.dispatchAll();
+ ArgumentCaptor<BroadcastReceiver> bcastRxCaptor = ArgumentCaptor.forClass(
+ BroadcastReceiver.class);
+ verify(mockContext).registerReceiver(bcastRxCaptor.capture(), any(IntentFilter.class));
+ verify(mockNative).start();
+ mPowerBcastReceiver = bcastRxCaptor.getValue();
+
+ assertTrue(mDut.isAvailable());
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ assertEquals("Binder links != unlinks to death (size)",
+ mBinderLinkToDeathCounter.mUniqueExecs.size(),
+ mBinderUnlinkToDeathCounter.mUniqueExecs.size());
+ assertEquals("Binder links != unlinks to death", mBinderLinkToDeathCounter.mUniqueExecs,
+ mBinderUnlinkToDeathCounter.mUniqueExecs);
+ }
+
+ /**
+ * Validate successful ranging flow.
+ */
+ @Test
+ public void testRangingFlow() throws Exception {
+ int numIter = 10;
+ RangingRequest[] requests = new RangingRequest[numIter];
+ List<Pair<List<RttResult>, List<RangingResult>>> results = new ArrayList<>();
+
+ for (int i = 0; i < numIter; ++i) {
+ requests[i] = RttTestUtils.getDummyRangingRequest((byte) i);
+ results.add(RttTestUtils.getDummyRangingResults(requests[i]));
+ }
+
+ // (1) request 10 ranging operations
+ for (int i = 0; i < numIter; ++i) {
+ mDut.startRanging(mockIbinder, mPackageName, null, requests[i], mockCallback);
+ }
+ mMockLooper.dispatchAll();
+
+ for (int i = 0; i < numIter; ++i) {
+ // (2) verify that request issued to native
+ verify(mockNative).rangeRequest(mIntCaptor.capture(), eq(requests[i]));
+ verifyWakeupSet();
+
+ // (3) native calls back with result
+ mDut.onRangingResults(mIntCaptor.getValue(), results.get(i).first);
+ mMockLooper.dispatchAll();
+
+ // (4) verify that results dispatched
+ verify(mockCallback).onRangingResults(results.get(i).second);
+ verifyWakeupCancelled();
+
+ // (5) replicate results - shouldn't dispatch another callback
+ mDut.onRangingResults(mIntCaptor.getValue(), results.get(i).first);
+ mMockLooper.dispatchAll();
+ }
+
+ verify(mockNative, atLeastOnce()).isReady();
+ verifyNoMoreInteractions(mockNative, mockCallback, mAlarmManager.getAlarmManager());
+ }
+
+ /**
+ * Validate a successful ranging flow with PeerHandles (i.e. verify translations)
+ */
+ @Test
+ public void testRangingFlowUsingAwarePeerHandles() throws Exception {
+ RangingRequest request = RttTestUtils.getDummyRangingRequest((byte) 0xA);
+ PeerHandle peerHandle1 = new PeerHandle(1022);
+ PeerHandle peerHandle2 = new PeerHandle(1023);
+ request.mRttPeers.add(ResponderConfig.fromWifiAwarePeerHandleWithDefaults(peerHandle1));
+ request.mRttPeers.add(ResponderConfig.fromWifiAwarePeerHandleWithDefaults(peerHandle2));
+ Map<Integer, byte[]> peerHandleToMacMap = new HashMap<>();
+ byte[] macAwarePeer1 = HexEncoding.decode("AABBCCDDEEFF".toCharArray(), false);
+ byte[] macAwarePeer2 = HexEncoding.decode("BBBBBBEEEEEE".toCharArray(), false);
+ peerHandleToMacMap.put(peerHandle1.peerId, macAwarePeer1);
+ peerHandleToMacMap.put(peerHandle2.peerId, macAwarePeer2);
+
+ AwareTranslatePeerHandlesToMac answer = new AwareTranslatePeerHandlesToMac(mDefaultUid,
+ peerHandleToMacMap);
+ doAnswer(answer).when(mockAwareManagerBinder).requestMacAddresses(anyInt(), any(), any());
+
+ // issue request
+ mDut.startRanging(mockIbinder, mPackageName, null, request, mockCallback);
+ mMockLooper.dispatchAll();
+
+ // verify that requested with MAC address translated from the PeerHandle issued to Native
+ verify(mockNative).rangeRequest(mIntCaptor.capture(), mRequestCaptor.capture());
+ verifyWakeupSet();
+
+ RangingRequest finalRequest = mRequestCaptor.getValue();
+ assertNotEquals("Request to native is not null", null, finalRequest);
+ assertEquals("Size of request", request.mRttPeers.size(), finalRequest.mRttPeers.size());
+ assertEquals("Aware peer 1 MAC", macAwarePeer1,
+ finalRequest.mRttPeers.get(finalRequest.mRttPeers.size() - 2).macAddress);
+ assertEquals("Aware peer 2 MAC", macAwarePeer2,
+ finalRequest.mRttPeers.get(finalRequest.mRttPeers.size() - 1).macAddress);
+
+ // issue results - but remove the one for peer #2
+ Pair<List<RttResult>, List<RangingResult>> results =
+ RttTestUtils.getDummyRangingResults(mRequestCaptor.getValue());
+ results.first.remove(results.first.size() - 1);
+ RangingResult removed = results.second.remove(results.second.size() - 1);
+ results.second.add(
+ new RangingResult(RangingResult.STATUS_FAIL, removed.getPeerHandle(), 0, 0, 0, 0));
+ mDut.onRangingResults(mIntCaptor.getValue(), results.first);
+ mMockLooper.dispatchAll();
+
+ // verify that results with MAC addresses filtered out and replaced by PeerHandles issued
+ // to callback
+ verify(mockCallback).onRangingResults(mListCaptor.capture());
+ verifyWakeupCancelled();
+
+ assertTrue(compareListContentsNoOrdering(results.second, mListCaptor.getValue()));
+
+ verify(mockNative, atLeastOnce()).isReady();
+ verifyNoMoreInteractions(mockNative, mockCallback, mAlarmManager.getAlarmManager());
+ }
+
+ /**
+ * Validate failed ranging flow (native failure).
+ */
+ @Test
+ public void testRangingFlowNativeFailure() throws Exception {
+ int numIter = 10;
+ RangingRequest[] requests = new RangingRequest[numIter];
+ List<Pair<List<RttResult>, List<RangingResult>>> results = new ArrayList<>();
+
+ for (int i = 0; i < numIter; ++i) {
+ requests[i] = RttTestUtils.getDummyRangingRequest((byte) i);
+ results.add(RttTestUtils.getDummyRangingResults(requests[i]));
+ }
+
+ // (1) request 10 ranging operations: fail the first one
+ when(mockNative.rangeRequest(anyInt(), any(RangingRequest.class))).thenReturn(false);
+ mDut.startRanging(mockIbinder, mPackageName, null, requests[0], mockCallback);
+ mMockLooper.dispatchAll();
+
+ when(mockNative.rangeRequest(anyInt(), any(RangingRequest.class))).thenReturn(true);
+ for (int i = 1; i < numIter; ++i) {
+ mDut.startRanging(mockIbinder, mPackageName, null, requests[i], mockCallback);
+ }
+ mMockLooper.dispatchAll();
+
+ for (int i = 0; i < numIter; ++i) {
+ // (2) verify that request issued to native
+ verify(mockNative).rangeRequest(mIntCaptor.capture(), eq(requests[i]));
+
+ // (3) verify that failure callback dispatched (for the HAL failure)
+ if (i == 0) {
+ verify(mockCallback).onRangingFailure(RangingResultCallback.STATUS_CODE_FAIL);
+ } else {
+ verifyWakeupSet();
+ }
+
+ // (4) on failed HAL: even if native calls back with result we shouldn't dispatch
+ // callback, otherwise expect result
+ mDut.onRangingResults(mIntCaptor.getValue(), results.get(i).first);
+ mMockLooper.dispatchAll();
+
+ if (i != 0) {
+ verify(mockCallback).onRangingResults(results.get(i).second);
+ verifyWakeupCancelled();
+ }
+ }
+
+ verify(mockNative, atLeastOnce()).isReady();
+ verifyNoMoreInteractions(mockNative, mockCallback, mAlarmManager.getAlarmManager());
+ }
+
+ /**
+ * Validate a ranging flow for an app whose LOCATION runtime permission is revoked.
+ */
+ @Test
+ public void testRangingRequestWithoutRuntimePermission() throws Exception {
+ RangingRequest request = RttTestUtils.getDummyRangingRequest((byte) 0);
+ Pair<List<RttResult>, List<RangingResult>> results = RttTestUtils.getDummyRangingResults(
+ request);
+
+ // (1) request ranging operation
+ mDut.startRanging(mockIbinder, mPackageName, null, request, mockCallback);
+ mMockLooper.dispatchAll();
+
+ // (2) verify that request issued to native
+ verify(mockNative).rangeRequest(mIntCaptor.capture(), eq(request));
+ verifyWakeupSet();
+
+ // (3) native calls back with result - should get a FAILED callback
+ when(mockPermissionUtil.checkCallersLocationPermission(eq(mPackageName),
+ anyInt())).thenReturn(false);
+
+ mDut.onRangingResults(mIntCaptor.getValue(), results.first);
+ mMockLooper.dispatchAll();
+
+ verify(mockCallback).onRangingFailure(eq(RangingResultCallback.STATUS_CODE_FAIL));
+ verifyWakeupCancelled();
+
+ verify(mockNative, atLeastOnce()).isReady();
+ verifyNoMoreInteractions(mockNative, mockCallback, mAlarmManager.getAlarmManager());
+ }
+
+ /**
+ * Validate that the ranging app's binder death clears record of request - no callbacks are
+ * attempted.
+ */
+ @Test
+ public void testBinderDeathOfRangingApp() throws Exception {
+ int numIter = 10;
+ RangingRequest[] requests = new RangingRequest[numIter];
+ List<Pair<List<RttResult>, List<RangingResult>>> results = new ArrayList<>();
+
+ for (int i = 0; i < numIter; ++i) {
+ requests[i] = RttTestUtils.getDummyRangingRequest((byte) i);
+ results.add(RttTestUtils.getDummyRangingResults(requests[i]));
+ }
+
+ // (1) request 10 ranging operations: even/odd with different UIDs
+ for (int i = 0; i < numIter; ++i) {
+ mDut.fakeUid = mDefaultUid + i % 2;
+ mDut.startRanging(mockIbinder, mPackageName, null, requests[i], mockCallback);
+ }
+ mMockLooper.dispatchAll();
+
+ // (2) capture death listeners
+ verify(mockIbinder, times(numIter)).linkToDeath(mDeathRecipientCaptor.capture(), anyInt());
+
+ for (int i = 0; i < numIter; ++i) {
+ // (3) verify first request and all odd requests issued to HAL
+ if (i == 0 || i % 2 == 1) {
+ verify(mockNative).rangeRequest(mIntCaptor.capture(), eq(requests[i]));
+ verifyWakeupSet();
+ }
+
+ // (4) trigger first death recipient (which will map to the even UID)
+ if (i == 0) {
+ mDeathRecipientCaptor.getAllValues().get(0).binderDied();
+ mMockLooper.dispatchAll();
+
+ verify(mockNative).rangeCancel(eq(mIntCaptor.getValue()),
+ (ArrayList) mListCaptor.capture());
+ RangingRequest request0 = requests[0];
+ assertEquals(request0.mRttPeers.size(), mListCaptor.getValue().size());
+ assertArrayEquals(HexEncoding.decode("000102030400".toCharArray(), false),
+ (byte[]) mListCaptor.getValue().get(0));
+ assertArrayEquals(HexEncoding.decode("0A0B0C0D0E00".toCharArray(), false),
+ (byte[]) mListCaptor.getValue().get(1));
+ assertArrayEquals(HexEncoding.decode("080908070605".toCharArray(), false),
+ (byte[]) mListCaptor.getValue().get(2));
+ }
+
+ // (5) native calls back with all results - should get requests for the odd attempts and
+ // should only get callbacks for the odd attempts (the non-dead UID), but this simulates
+ // invalid results (or possibly the firmware not cancelling some requests)
+ mDut.onRangingResults(mIntCaptor.getValue(), results.get(i).first);
+ mMockLooper.dispatchAll();
+ if (i == 0) {
+ verifyWakeupCancelled(); // as the first (dispatched) request is aborted
+ }
+ if (i % 2 == 1) {
+ verify(mockCallback).onRangingResults(results.get(i).second);
+ verifyWakeupCancelled();
+ }
+ }
+
+ verify(mockNative, atLeastOnce()).isReady();
+ verifyNoMoreInteractions(mockNative, mockCallback, mAlarmManager.getAlarmManager());
+ }
+
+ /**
+ * Validate that a ranging app which uses WorkSource and dies (binder death) results in the
+ * request cleanup.
+ */
+ @Test
+ public void testBinderDeathWithWorkSource() throws Exception {
+ WorkSource ws = new WorkSource(100);
+
+ RangingRequest request = RttTestUtils.getDummyRangingRequest((byte) 0);
+ Pair<List<RttResult>, List<RangingResult>> results = RttTestUtils.getDummyRangingResults(
+ request);
+
+ // (1) request ranging operation
+ mDut.startRanging(mockIbinder, mPackageName, ws, request, mockCallback);
+ mMockLooper.dispatchAll();
+
+ verify(mockIbinder).linkToDeath(mDeathRecipientCaptor.capture(), anyInt());
+ verify(mockNative).rangeRequest(mIntCaptor.capture(), eq(request));
+ verifyWakeupSet();
+
+ // (2) execute binder death
+ mDeathRecipientCaptor.getValue().binderDied();
+ mMockLooper.dispatchAll();
+
+ verify(mockNative).rangeCancel(eq(mIntCaptor.getValue()), any());
+ verifyWakeupCancelled();
+
+ // (3) provide results back - should be ignored
+ mDut.onRangingResults(mIntCaptor.getValue(), results.first);
+ mMockLooper.dispatchAll();
+
+ verify(mockNative, atLeastOnce()).isReady();
+ verifyNoMoreInteractions(mockNative, mockCallback, mAlarmManager.getAlarmManager());
+ }
+
+ /**
+ * Validate that when a cancelRanging is called, using the same work source specification as the
+ * request, that the request is cancelled.
+ */
+ @Test
+ public void testCancelRangingFullMatch() throws Exception {
+ int uid1 = 10;
+ int uid2 = 20;
+ int uid3 = 30;
+ WorkSource worksourceRequest = new WorkSource(uid1);
+ worksourceRequest.add(uid2);
+ worksourceRequest.add(uid3);
+ WorkSource worksourceCancel = new WorkSource(uid2);
+ worksourceCancel.add(uid3);
+ worksourceCancel.add(uid1);
+
+ RangingRequest request = RttTestUtils.getDummyRangingRequest((byte) 0);
+ Pair<List<RttResult>, List<RangingResult>> results = RttTestUtils.getDummyRangingResults(
+ request);
+
+ // (1) request ranging operation
+ mDut.startRanging(mockIbinder, mPackageName, worksourceRequest, request, mockCallback);
+ mMockLooper.dispatchAll();
+
+ // (2) verify that request issued to native
+ verify(mockNative).rangeRequest(mIntCaptor.capture(), eq(request));
+ verifyWakeupSet();
+
+ // (3) cancel the request
+ mDut.cancelRanging(worksourceCancel);
+ mMockLooper.dispatchAll();
+
+ verify(mockNative).rangeCancel(eq(mIntCaptor.getValue()), any());
+ verifyWakeupCancelled();
+
+ // (4) send results back from native
+ mDut.onRangingResults(mIntCaptor.getValue(), results.first);
+ mMockLooper.dispatchAll();
+
+ verify(mockNative, atLeastOnce()).isReady();
+ verifyNoMoreInteractions(mockNative, mockCallback, mAlarmManager.getAlarmManager());
+ }
+
+ /**
+ * Validate that when a cancelRanging is called - but specifies a subset of the WorkSource
+ * uids then the ranging proceeds.
+ */
+ @Test
+ public void testCancelRangingPartialMatch() throws Exception {
+ int uid1 = 10;
+ int uid2 = 20;
+ int uid3 = 30;
+ WorkSource worksourceRequest = new WorkSource(uid1);
+ worksourceRequest.add(uid2);
+ worksourceRequest.add(uid3);
+ WorkSource worksourceCancel = new WorkSource(uid1);
+ worksourceCancel.add(uid2);
+
+ RangingRequest request = RttTestUtils.getDummyRangingRequest((byte) 0);
+ Pair<List<RttResult>, List<RangingResult>> results = RttTestUtils.getDummyRangingResults(
+ request);
+
+ // (1) request ranging operation
+ mDut.startRanging(mockIbinder, mPackageName, worksourceRequest, request, mockCallback);
+ mMockLooper.dispatchAll();
+
+ // (2) verify that request issued to native
+ verify(mockNative).rangeRequest(mIntCaptor.capture(), eq(request));
+ verifyWakeupSet();
+
+ // (3) cancel the request
+ mDut.cancelRanging(worksourceCancel);
+
+ // (4) send results back from native
+ mDut.onRangingResults(mIntCaptor.getValue(), results.first);
+ mMockLooper.dispatchAll();
+
+ verify(mockCallback).onRangingResults(results.second);
+ verifyWakeupCancelled();
+
+ verify(mockNative, atLeastOnce()).isReady();
+ verifyNoMoreInteractions(mockNative, mockCallback, mAlarmManager.getAlarmManager());
+ }
+
+ /**
+ * Validate that when an unexpected result is provided by the Native it is not propagated to
+ * caller (unexpected = different command ID).
+ */
+ @Test
+ public void testUnexpectedResult() throws Exception {
+ RangingRequest request = RttTestUtils.getDummyRangingRequest((byte) 0);
+ Pair<List<RttResult>, List<RangingResult>> results = RttTestUtils.getDummyRangingResults(
+ request);
+
+ // (1) request ranging operation
+ mDut.startRanging(mockIbinder, mPackageName, null, request, mockCallback);
+ mMockLooper.dispatchAll();
+
+ // (2) verify that request issued to native
+ verify(mockNative).rangeRequest(mIntCaptor.capture(), eq(request));
+ verifyWakeupSet();
+
+ // (3) native calls back with result - but wrong ID
+ mDut.onRangingResults(mIntCaptor.getValue() + 1,
+ RttTestUtils.getDummyRangingResults(null).first);
+ mMockLooper.dispatchAll();
+
+ // (4) now send results with correct ID (different set of results to differentiate)
+ mDut.onRangingResults(mIntCaptor.getValue(), results.first);
+ mMockLooper.dispatchAll();
+
+ // (5) verify that results dispatched
+ verify(mockCallback).onRangingResults(results.second);
+ verifyWakeupCancelled();
+
+ verify(mockNative, atLeastOnce()).isReady();
+ verifyNoMoreInteractions(mockNative, mockCallback, mAlarmManager.getAlarmManager());
+ }
+
+ /**
+ * Validate that the HAL returns results with "missing" entries (i.e. some requests don't get
+ * results) they are filled-in with FAILED results.
+ */
+ @Test
+ public void testMissingResults() throws Exception {
+ RangingRequest request = RttTestUtils.getDummyRangingRequest((byte) 0);
+ Pair<List<RttResult>, List<RangingResult>> results = RttTestUtils.getDummyRangingResults(
+ request);
+ results.first.remove(2); // remove a direct AWARE request
+ RangingResult removed = results.second.remove(2);
+ results.second.add(
+ new RangingResult(RangingResult.STATUS_FAIL, removed.getMacAddress(), 0, 0, 0, 0));
+ results.first.remove(0); // remove an AP request
+ removed = results.second.remove(0);
+ results.second.add(
+ new RangingResult(RangingResult.STATUS_FAIL, removed.getMacAddress(), 0, 0, 0, 0));
+
+ // (1) request ranging operation
+ mDut.startRanging(mockIbinder, mPackageName, null, request, mockCallback);
+ mMockLooper.dispatchAll();
+
+ // (2) verify that request issued to native
+ verify(mockNative).rangeRequest(mIntCaptor.capture(), eq(request));
+ verifyWakeupSet();
+
+ // (3) return results with missing entries
+ mDut.onRangingResults(mIntCaptor.getValue(), results.first);
+ mMockLooper.dispatchAll();
+
+ // (5) verify that (full) results dispatched
+ verify(mockCallback).onRangingResults(mListCaptor.capture());
+ assertTrue(compareListContentsNoOrdering(results.second, mListCaptor.getValue()));
+ verifyWakeupCancelled();
+
+ verify(mockNative, atLeastOnce()).isReady();
+ verifyNoMoreInteractions(mockNative, mockCallback, mAlarmManager.getAlarmManager());
+ }
+
+ /**
+ * Validate that when the HAL times out we fail, clean-up the queue and move to the next
+ * request.
+ */
+ @Test
+ public void testRangingTimeout() throws Exception {
+ RangingRequest request1 = RttTestUtils.getDummyRangingRequest((byte) 1);
+ RangingRequest request2 = RttTestUtils.getDummyRangingRequest((byte) 2);
+ Pair<List<RttResult>, List<RangingResult>> result1 = RttTestUtils.getDummyRangingResults(
+ request1);
+ Pair<List<RttResult>, List<RangingResult>> result2 = RttTestUtils.getDummyRangingResults(
+ request2);
+
+ // (1) request 2 ranging operation
+ mDut.startRanging(mockIbinder, mPackageName, null, request1, mockCallback);
+ mDut.startRanging(mockIbinder, mPackageName, null, request2, mockCallback);
+ mMockLooper.dispatchAll();
+
+ // verify that request 1 issued to native
+ verify(mockNative).rangeRequest(mIntCaptor.capture(), eq(request1));
+ int cmdId1 = mIntCaptor.getValue();
+ verifyWakeupSet();
+
+ // (2) time-out
+ mAlarmManager.dispatch(RttServiceImpl.HAL_RANGING_TIMEOUT_TAG);
+ mMockLooper.dispatchAll();
+
+ // verify that: failure callback + request 2 issued to native
+ verify(mockNative).rangeCancel(eq(cmdId1), any());
+ verify(mockCallback).onRangingFailure(RangingResultCallback.STATUS_CODE_FAIL);
+ verify(mockNative).rangeRequest(mIntCaptor.capture(), eq(request2));
+ verifyWakeupSet();
+
+ // (3) send both result 1 and result 2
+ mDut.onRangingResults(cmdId1, result1.first);
+ mDut.onRangingResults(mIntCaptor.getValue(), result2.first);
+ mMockLooper.dispatchAll();
+
+ // verify that only result 2 is forwarded to client
+ verify(mockCallback).onRangingResults(result2.second);
+ verifyWakeupCancelled();
+
+ verify(mockNative, atLeastOnce()).isReady();
+ verifyNoMoreInteractions(mockNative, mockCallback, mAlarmManager.getAlarmManager());
+ }
+
+ /**
+ * Validate that ranging requests from background apps are throttled. The sequence is:
+ * - Time 1: Background request -> ok
+ * - Time 2 = t1 + 0.5gap: Background request -> fail (throttled)
+ * - Time 3 = t1 + 1.1gap: Background request -> ok
+ * - Time 4 = t3 + small: Foreground request -> ok
+ * - Time 5 = t4 + small: Background request -> fail (throttled)
+ */
+ @Test
+ public void testRangingThrottleBackground() throws Exception {
+ RangingRequest request1 = RttTestUtils.getDummyRangingRequest((byte) 1);
+ RangingRequest request2 = RttTestUtils.getDummyRangingRequest((byte) 2);
+ RangingRequest request3 = RttTestUtils.getDummyRangingRequest((byte) 3);
+ RangingRequest request4 = RttTestUtils.getDummyRangingRequest((byte) 4);
+ RangingRequest request5 = RttTestUtils.getDummyRangingRequest((byte) 5);
+
+ Pair<List<RttResult>, List<RangingResult>> result1 = RttTestUtils.getDummyRangingResults(
+ request1);
+ Pair<List<RttResult>, List<RangingResult>> result3 = RttTestUtils.getDummyRangingResults(
+ request3);
+ Pair<List<RttResult>, List<RangingResult>> result4 = RttTestUtils.getDummyRangingResults(
+ request4);
+
+ InOrder cbInorder = inOrder(mockCallback);
+
+ ClockAnswer clock = new ClockAnswer();
+ doAnswer(clock).when(mockClock).getElapsedSinceBootMillis();
+ when(mockActivityManager.getUidImportance(anyInt())).thenReturn(
+ ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE); // far background
+
+ // (1) issue a request at time t1: should be dispatched since first one!
+ clock.time = 100;
+ mDut.startRanging(mockIbinder, mPackageName, null, request1, mockCallback);
+ mMockLooper.dispatchAll();
+
+ verify(mockNative).rangeRequest(mIntCaptor.capture(), eq(request1));
+ verifyWakeupSet();
+
+ // (1.1) get result
+ mDut.onRangingResults(mIntCaptor.getValue(), result1.first);
+ mMockLooper.dispatchAll();
+
+ cbInorder.verify(mockCallback).onRangingResults(result1.second);
+ verifyWakeupCancelled();
+
+ // (2) issue a request at time t2 = t1 + 0.5 gap: should be rejected (throttled)
+ clock.time = 100 + RttServiceImpl.BACKGROUND_PROCESS_EXEC_GAP_MS / 2;
+ mDut.startRanging(mockIbinder, mPackageName, null, request2, mockCallback);
+ mMockLooper.dispatchAll();
+
+ cbInorder.verify(mockCallback).onRangingFailure(RangingResultCallback.STATUS_CODE_FAIL);
+
+ // (3) issue a request at time t3 = t1 + 1.1 gap: should be dispatched since enough time
+ clock.time = 100 + RttServiceImpl.BACKGROUND_PROCESS_EXEC_GAP_MS * 11 / 10;
+ mDut.startRanging(mockIbinder, mPackageName, null, request3, mockCallback);
+ mMockLooper.dispatchAll();
+
+ verify(mockNative).rangeRequest(mIntCaptor.capture(), eq(request3));
+ verifyWakeupSet();
+
+ // (3.1) get result
+ mDut.onRangingResults(mIntCaptor.getValue(), result3.first);
+ mMockLooper.dispatchAll();
+
+ cbInorder.verify(mockCallback).onRangingResults(result3.second);
+ verifyWakeupCancelled();
+
+ // (4) issue a foreground request at t4 = t3 + small: should be dispatched (foreground!)
+ when(mockActivityManager.getUidImportance(anyInt())).thenReturn(
+ ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND);
+
+ clock.time = clock.time + 5;
+ mDut.startRanging(mockIbinder, mPackageName, null, request4, mockCallback);
+ mMockLooper.dispatchAll();
+
+ verify(mockNative).rangeRequest(mIntCaptor.capture(), eq(request4));
+ verifyWakeupSet();
+
+ // (4.1) get result
+ mDut.onRangingResults(mIntCaptor.getValue(), result4.first);
+ mMockLooper.dispatchAll();
+
+ cbInorder.verify(mockCallback).onRangingResults(result4.second);
+ verifyWakeupCancelled();
+
+ // (5) issue a background request at t5 = t4 + small: should be rejected (throttled)
+ when(mockActivityManager.getUidImportance(anyInt())).thenReturn(
+ ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE);
+
+ clock.time = clock.time + 5;
+ mDut.startRanging(mockIbinder, mPackageName, null, request5, mockCallback);
+ mMockLooper.dispatchAll();
+
+ cbInorder.verify(mockCallback).onRangingFailure(RangingResultCallback.STATUS_CODE_FAIL);
+
+ verify(mockNative, atLeastOnce()).isReady();
+ verifyNoMoreInteractions(mockNative, mockCallback, mAlarmManager.getAlarmManager());
+ }
+
+ /**
+ * Validate that throttling of background request handles multiple work source correctly:
+ * - Time t1: background request uid=10: ok
+ * - Time t2 = t1+small: background request ws={10,20}: ok
+ * - Time t3 = t1+gap: background request uid=10: fail (throttled)
+ */
+ @Test
+ public void testRangingThrottleBackgroundWorkSources() throws Exception {
+ WorkSource wsReq1 = new WorkSource(10);
+ WorkSource wsReq2 = new WorkSource(10);
+ wsReq2.add(20);
+
+ RangingRequest request1 = RttTestUtils.getDummyRangingRequest((byte) 1);
+ RangingRequest request2 = RttTestUtils.getDummyRangingRequest((byte) 2);
+ RangingRequest request3 = RttTestUtils.getDummyRangingRequest((byte) 3);
+
+ Pair<List<RttResult>, List<RangingResult>> result1 = RttTestUtils.getDummyRangingResults(
+ request1);
+ Pair<List<RttResult>, List<RangingResult>> result2 = RttTestUtils.getDummyRangingResults(
+ request2);
+
+ InOrder cbInorder = inOrder(mockCallback);
+
+ ClockAnswer clock = new ClockAnswer();
+ doAnswer(clock).when(mockClock).getElapsedSinceBootMillis();
+ when(mockActivityManager.getUidImportance(anyInt())).thenReturn(
+ ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE); // far background
+
+ // (1) issue a request at time t1 for {10}: should be dispatched since first one!
+ clock.time = 100;
+ mDut.startRanging(mockIbinder, mPackageName, wsReq1, request1, mockCallback);
+ mMockLooper.dispatchAll();
+
+ verify(mockNative).rangeRequest(mIntCaptor.capture(), eq(request1));
+ verifyWakeupSet();
+
+ // (1.1) get result
+ mDut.onRangingResults(mIntCaptor.getValue(), result1.first);
+ mMockLooper.dispatchAll();
+
+ cbInorder.verify(mockCallback).onRangingResults(result1.second);
+ verifyWakeupCancelled();
+
+ // (2) issue a request at time t2 = t1 + 0.5 gap for {10,20}: should be dispatched since
+ // uid=20 should not be throttled
+ clock.time = 100 + RttServiceImpl.BACKGROUND_PROCESS_EXEC_GAP_MS / 2;
+ mDut.startRanging(mockIbinder, mPackageName, wsReq2, request2, mockCallback);
+ mMockLooper.dispatchAll();
+
+ verify(mockNative).rangeRequest(mIntCaptor.capture(), eq(request2));
+ verifyWakeupSet();
+
+ // (2.1) get result
+ mDut.onRangingResults(mIntCaptor.getValue(), result2.first);
+ mMockLooper.dispatchAll();
+
+ cbInorder.verify(mockCallback).onRangingResults(result2.second);
+ verifyWakeupCancelled();
+
+ // (3) issue a request at t3 = t1 + 1.1 * gap for {10}: should be rejected (throttled)
+ clock.time = 100 + RttServiceImpl.BACKGROUND_PROCESS_EXEC_GAP_MS * 11 / 10;
+ mDut.startRanging(mockIbinder, mPackageName, wsReq1, request3, mockCallback);
+ mMockLooper.dispatchAll();
+
+ cbInorder.verify(mockCallback).onRangingFailure(RangingResultCallback.STATUS_CODE_FAIL);
+
+ verify(mockNative, atLeastOnce()).isReady();
+ verifyNoMoreInteractions(mockNative, mockCallback, mAlarmManager.getAlarmManager());
+ }
+
+ /**
+ * Validate that flooding the service with ranging requests will cause it to start rejecting
+ * rejects from the flooding uid. Single UID.
+ */
+ @Test
+ public void testRejectFloodingRequestsSingleUid() throws Exception {
+ runFloodRequestsTest(true);
+ }
+
+ /**
+ * Validate that flooding the service with ranging requests will cause it to start rejecting
+ * rejects from the flooding uid. WorkSource (all identical).
+ */
+ @Test
+ public void testRejectFloodingRequestsIdenticalWorksources() throws Exception {
+ runFloodRequestsTest(false);
+ }
+
+ /**
+ * Validate that flooding the service with ranging requests will cause it to start rejecting
+ * rejects from the flooding uid. WorkSource (with one constant UID but other varying UIDs -
+ * the varying UIDs should prevent the flood throttle)
+ */
+ @Test
+ public void testDontRejectFloodingRequestsVariousUids() throws Exception {
+ RangingRequest request = RttTestUtils.getDummyRangingRequest((byte) 1);
+ WorkSource ws = new WorkSource(10);
+
+ // 1. issue a request
+ mDut.startRanging(mockIbinder, mPackageName, ws, request, mockCallback);
+ mMockLooper.dispatchAll();
+
+ verify(mockNative).rangeRequest(mIntCaptor.capture(), eq(request));
+ verifyWakeupSet();
+
+ // 2. issue FLOOD LEVEL requests + 10 at various UIDs - no failure expected
+ for (int i = 0; i < RttServiceImpl.MAX_QUEUED_PER_UID + 10; ++i) {
+ WorkSource wsExtra = new WorkSource(ws);
+ wsExtra.add(11 + i);
+ mDut.startRanging(mockIbinder, mPackageName, wsExtra, request, mockCallback);
+ }
+ mMockLooper.dispatchAll();
+
+ // 3. clear queue
+ mDut.disable();
+ mMockLooper.dispatchAll();
+
+ verifyWakeupCancelled();
+ verify(mockNative).rangeCancel(eq(mIntCaptor.getValue()), any());
+ verify(mockCallback, times(RttServiceImpl.MAX_QUEUED_PER_UID + 11)).onRangingFailure(
+ RangingResultCallback.STATUS_CODE_FAIL_RTT_NOT_AVAILABLE);
+
+ verify(mockNative, atLeastOnce()).isReady();
+ verifyNoMoreInteractions(mockNative, mockCallback, mAlarmManager.getAlarmManager());
+ }
+
+ /**
+ * Utility to run configurable tests for flooding range requests.
+ * - Execute a single request
+ * - Flood service with requests: using same ID or same WorkSource
+ * - Provide results (to clear queue) and execute another test: validate succeeds
+ */
+ private void runFloodRequestsTest(boolean useUids) throws Exception {
+ RangingRequest request = RttTestUtils.getDummyRangingRequest((byte) 1);
+ Pair<List<RttResult>, List<RangingResult>> result = RttTestUtils.getDummyRangingResults(
+ request);
+
+ WorkSource ws = new WorkSource();
+ ws.add(10);
+ ws.add(20);
+ ws.add(30);
+
+ InOrder cbInorder = inOrder(mockCallback);
+ InOrder nativeInorder = inOrder(mockNative);
+
+ // 1. issue a request
+ mDut.startRanging(mockIbinder, mPackageName, useUids ? null : ws, request, mockCallback);
+ mMockLooper.dispatchAll();
+
+ nativeInorder.verify(mockNative).rangeRequest(mIntCaptor.capture(), eq(request));
+ verifyWakeupSet();
+
+ // 2. issue FLOOD LEVEL requests + 10: should get 11 failures (10 extra + 1 original)
+ for (int i = 0; i < RttServiceImpl.MAX_QUEUED_PER_UID + 10; ++i) {
+ mDut.startRanging(mockIbinder, mPackageName, useUids ? null : ws, request,
+ mockCallback);
+ }
+ mMockLooper.dispatchAll();
+
+ cbInorder.verify(mockCallback, times(11)).onRangingFailure(
+ RangingResultCallback.STATUS_CODE_FAIL);
+
+ // 3. provide results
+ mDut.onRangingResults(mIntCaptor.getValue(), result.first);
+ mMockLooper.dispatchAll();
+
+ cbInorder.verify(mockCallback).onRangingResults(result.second);
+ verifyWakeupCancelled();
+
+ nativeInorder.verify(mockNative).rangeRequest(mIntCaptor.capture(), eq(request));
+ verifyWakeupSet();
+
+ // 4. issue a request: don't expect a failure
+ mDut.startRanging(mockIbinder, mPackageName, useUids ? null : ws, request, mockCallback);
+ mMockLooper.dispatchAll();
+
+ // 5. clear queue
+ mDut.disable();
+ mMockLooper.dispatchAll();
+
+ verifyWakeupCancelled();
+ nativeInorder.verify(mockNative).rangeCancel(eq(mIntCaptor.getValue()), any());
+ cbInorder.verify(mockCallback, times(RttServiceImpl.MAX_QUEUED_PER_UID)).onRangingFailure(
+ RangingResultCallback.STATUS_CODE_FAIL_RTT_NOT_AVAILABLE);
+
+ verify(mockNative, atLeastOnce()).isReady();
+ verifyNoMoreInteractions(mockNative, mockCallback, mAlarmManager.getAlarmManager());
+ }
+
+ /**
+ * Validate that when Wi-Fi gets disabled (HAL level) the ranging queue gets cleared.
+ */
+ @Test
+ public void testDisableWifiFlow() throws Exception {
+ runDisableRttFlow(true);
+ }
+
+ /**
+ * Validate that when Doze mode starts, RTT gets disabled and the ranging queue gets cleared.
+ */
+ @Test
+ public void testDozeModeFlow() throws Exception {
+ runDisableRttFlow(false);
+ }
+
+ /**
+ * Actually execute the disable RTT flow: either by disabling Wi-Fi or enabling doze.
+ *
+ * @param disableWifi true to disable Wi-Fi, false to enable doze
+ */
+ private void runDisableRttFlow(boolean disableWifi) throws Exception {
+ RangingRequest request1 = RttTestUtils.getDummyRangingRequest((byte) 1);
+ RangingRequest request2 = RttTestUtils.getDummyRangingRequest((byte) 2);
+ RangingRequest request3 = RttTestUtils.getDummyRangingRequest((byte) 3);
+
+ IRttCallback mockCallback2 = mock(IRttCallback.class);
+ IRttCallback mockCallback3 = mock(IRttCallback.class);
+
+ // (1) request 2 ranging operations: request 1 should be sent to HAL
+ mDut.startRanging(mockIbinder, mPackageName, null, request1, mockCallback);
+ mDut.startRanging(mockIbinder, mPackageName, null, request2, mockCallback2);
+ mMockLooper.dispatchAll();
+
+ verify(mockNative).rangeRequest(mIntCaptor.capture(), eq(request1));
+ verifyWakeupSet();
+
+ // (2) disable RTT: all requests should "fail"
+ if (disableWifi) {
+ when(mockNative.isReady()).thenReturn(false);
+ mDut.disable();
+ } else {
+ simulatePowerStateChangeDoze(true);
+ }
+ mMockLooper.dispatchAll();
+
+ assertFalse(mDut.isAvailable());
+ validateCorrectRttStatusChangeBroadcast(false);
+ verify(mockNative).rangeCancel(eq(mIntCaptor.getValue()), any());
+ verify(mockCallback).onRangingFailure(
+ RangingResultCallback.STATUS_CODE_FAIL_RTT_NOT_AVAILABLE);
+ verify(mockCallback2).onRangingFailure(
+ RangingResultCallback.STATUS_CODE_FAIL_RTT_NOT_AVAILABLE);
+ verifyWakeupCancelled();
+
+ // (3) issue another request: it should fail
+ mDut.startRanging(mockIbinder, mPackageName, null, request3, mockCallback3);
+ mMockLooper.dispatchAll();
+
+ verify(mockCallback3).onRangingFailure(
+ RangingResultCallback.STATUS_CODE_FAIL_RTT_NOT_AVAILABLE);
+
+ // (4) enable RTT: nothing should happen (no requests in queue!)
+ if (disableWifi) {
+ when(mockNative.isReady()).thenReturn(true);
+ mDut.enable();
+ } else {
+ simulatePowerStateChangeDoze(false);
+ }
+ mMockLooper.dispatchAll();
+
+ assertTrue(mDut.isAvailable());
+ validateCorrectRttStatusChangeBroadcast(true);
+ verify(mockNative, atLeastOnce()).isReady();
+ verifyNoMoreInteractions(mockNative, mockCallback, mockCallback2, mockCallback3,
+ mAlarmManager.getAlarmManager());
+ }
+
+ /*
+ * Utilities
+ */
+
+ /**
+ * Simulate power state change due to doze. Changes the power manager return values and
+ * dispatches a broadcast.
+ */
+ private void simulatePowerStateChangeDoze(boolean isDozeOn) {
+ when(mMockPowerManager.isDeviceIdleMode()).thenReturn(isDozeOn);
+
+ Intent intent = new Intent(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
+ mPowerBcastReceiver.onReceive(mockContext, intent);
+ }
+
+ private void verifyWakeupSet() {
+ mInOrder.verify(mAlarmManager.getAlarmManager()).setExact(anyInt(), anyLong(),
+ eq(RttServiceImpl.HAL_RANGING_TIMEOUT_TAG), any(AlarmManager.OnAlarmListener.class),
+ any(Handler.class));
+ }
+
+ private void verifyWakeupCancelled() {
+ mInOrder.verify(mAlarmManager.getAlarmManager()).cancel(
+ any(AlarmManager.OnAlarmListener.class));
+ }
+
+ /**
+ * Validates that the broadcast sent on RTT status change is correct.
+ *
+ * @param expectedEnabled The expected change status - i.e. are we expected to announce that
+ * RTT is enabled (true) or disabled (false).
+ */
+ private void validateCorrectRttStatusChangeBroadcast(boolean expectedEnabled) {
+ ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);
+
+ mInOrder.verify(mockContext).sendBroadcastAsUser(intent.capture(), eq(UserHandle.ALL));
+ assertEquals(intent.getValue().getAction(), WifiRttManager.ACTION_WIFI_RTT_STATE_CHANGED);
+ }
+
+ private class AwareTranslatePeerHandlesToMac extends MockAnswerUtil.AnswerWithArguments {
+ private int mExpectedUid;
+ private Map<Integer, byte[]> mPeerIdToMacMap;
+
+ AwareTranslatePeerHandlesToMac(int expectedUid, Map<Integer, byte[]> peerIdToMacMap) {
+ mExpectedUid = expectedUid;
+ mPeerIdToMacMap = peerIdToMacMap;
+ }
+
+ public void answer(int uid, List<Integer> peerIds, IWifiAwareMacAddressProvider callback) {
+ assertEquals("Invalid UID", mExpectedUid, uid);
+
+ Map<Integer, byte[]> result = new HashMap<>();
+ for (Integer peerId: peerIds) {
+ byte[] mac = mPeerIdToMacMap.get(peerId);
+ if (mac == null) {
+ continue;
+ }
+
+ result.put(peerId, mac);
+ }
+
+ try {
+ callback.macAddress(result);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private class BinderDeathAnswerBase extends MockAnswerUtil.AnswerWithArguments {
+ protected Set<IBinder.DeathRecipient> mUniqueExecs = new HashSet<>();
+ }
+
+ private class BinderLinkToDeathAnswer extends BinderDeathAnswerBase {
+ public void answer(IBinder.DeathRecipient recipient, int flags) {
+ mUniqueExecs.add(recipient);
+ }
+ }
+
+ private class BinderUnlinkToDeathAnswer extends BinderDeathAnswerBase {
+ public boolean answer(IBinder.DeathRecipient recipient, int flags) {
+ mUniqueExecs.add(recipient);
+ return true;
+ }
+ }
+
+ private class ClockAnswer extends MockAnswerUtil.AnswerWithArguments {
+ public long time;
+
+ public long answer() {
+ return time;
+ }
+ }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/rtt/RttTestUtils.java b/tests/wifitests/src/com/android/server/wifi/rtt/RttTestUtils.java
new file mode 100644
index 0000000..db3cd17
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/rtt/RttTestUtils.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wifi.rtt;
+
+import android.hardware.wifi.V1_0.RttResult;
+import android.hardware.wifi.V1_0.RttStatus;
+import android.net.wifi.ScanResult;
+import android.net.wifi.rtt.RangingRequest;
+import android.net.wifi.rtt.RangingResult;
+import android.net.wifi.rtt.ResponderConfig;
+import android.util.Pair;
+
+import libcore.util.HexEncoding;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Utilities for the Rtt unit test suite.
+ */
+public class RttTestUtils {
+ /**
+ * Compare the two lists and return true for equality, false otherwise. The two lists are
+ * considered identical if they have the same number of elements and contain equal elements
+ * (equality of elements using the equal() operator of the component objects).
+ *
+ * Note: null != empty list
+ */
+ public static boolean compareListContentsNoOrdering(List a, List b) {
+ if (a == b) {
+ return true;
+ }
+ if (a == null || b == null) {
+ return false; // at this point they're not both null
+ }
+ if (a.size() != b.size()) { // at this point neither is null
+ return false;
+ }
+ return a.containsAll(b) && b.containsAll(a);
+ }
+
+ /**
+ * Returns a dummy ranging request with 2 requests:
+ * - First: 802.11mc capable
+ * - Second: 802.11mc not capable
+ */
+ public static RangingRequest getDummyRangingRequest(byte lastMacByte) {
+ RangingRequest.Builder builder = new RangingRequest.Builder();
+
+ ScanResult scan1 = new ScanResult();
+ scan1.BSSID = "00:01:02:03:04:" + String.format("%02d", lastMacByte);
+ scan1.setFlag(ScanResult.FLAG_80211mc_RESPONDER);
+ ScanResult scan2 = new ScanResult();
+ scan2.BSSID = "0A:0B:0C:0D:0E:" + String.format("%02d", lastMacByte);
+ byte[] mac1 = HexEncoding.decode("080908070605".toCharArray(), false);
+
+ builder.addAccessPoint(scan1);
+ builder.addAccessPoint(scan2);
+ builder.addWifiAwarePeer(mac1);
+
+ return builder.build();
+ }
+
+ /**
+ * Returns a matched set of dummy ranging results: HAL RttResult and the public API
+ * RangingResult.
+ *
+ * @param request If non-null will be used as a template (BSSID) for the range results.
+ */
+ public static Pair<List<RttResult>, List<RangingResult>> getDummyRangingResults(
+ RangingRequest request) {
+ int rangeCmBase = 15;
+ int rangeStdDevCmBase = 3;
+ int rssiBase = -20;
+ long rangeTimestampBase = 666;
+ List<RttResult> halResults = new ArrayList<>();
+ List<RangingResult> results = new ArrayList<>();
+
+ if (request != null) {
+ for (ResponderConfig peer: request.mRttPeers) {
+ RangingResult rangingResult;
+ if (peer.peerHandle == null) {
+ rangingResult = new RangingResult(RangingResult.STATUS_SUCCESS,
+ peer.macAddress, rangeCmBase++, rangeStdDevCmBase++, rssiBase++,
+ rangeTimestampBase++);
+ } else {
+ rangingResult = new RangingResult(RangingResult.STATUS_SUCCESS,
+ peer.peerHandle, rangeCmBase++, rangeStdDevCmBase++, rssiBase++,
+ rangeTimestampBase++);
+ }
+ results.add(rangingResult);
+ halResults.add(getMatchingRttResult(rangingResult, peer.macAddress));
+ }
+ } else {
+ results.add(new RangingResult(RangingResult.STATUS_SUCCESS,
+ HexEncoding.decode("100102030405".toCharArray(), false), rangeCmBase++,
+ rangeStdDevCmBase++, rssiBase++, rangeTimestampBase++));
+ results.add(new RangingResult(RangingResult.STATUS_SUCCESS,
+ HexEncoding.decode("1A0B0C0D0E0F".toCharArray(), false), rangeCmBase++,
+ rangeStdDevCmBase++, rssiBase++, rangeTimestampBase++));
+ results.add(new RangingResult(RangingResult.STATUS_SUCCESS,
+ HexEncoding.decode("080908070605".toCharArray(), false), rangeCmBase++,
+ rangeStdDevCmBase++, rssiBase++, rangeTimestampBase++));
+ halResults.add(getMatchingRttResult(results.get(0), null));
+ halResults.add(getMatchingRttResult(results.get(1), null));
+ halResults.add(getMatchingRttResult(results.get(2), null));
+ }
+
+ return new Pair<>(halResults, results);
+ }
+
+ private static RttResult getMatchingRttResult(RangingResult rangingResult, byte[] overrideMac) {
+ RttResult rttResult = new RttResult();
+ rttResult.status = rangingResult.getStatus() == RangingResult.STATUS_SUCCESS
+ ? RttStatus.SUCCESS : RttStatus.FAILURE;
+ System.arraycopy(overrideMac == null ? rangingResult.getMacAddress() : overrideMac, 0,
+ rttResult.addr, 0, 6);
+ rttResult.distanceInMm = rangingResult.getDistanceMm();
+ rttResult.distanceSdInMm = rangingResult.getDistanceStdDevMm();
+ rttResult.rssi = rangingResult.getRssi();
+ rttResult.timeStampInUs = rangingResult.getRangingTimestampUs();
+
+ return rttResult;
+ }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/scanner/BackgroundScanSchedulerTest.java b/tests/wifitests/src/com/android/server/wifi/scanner/BackgroundScanSchedulerTest.java
index c728d5f..e02fe77 100644
--- a/tests/wifitests/src/com/android/server/wifi/scanner/BackgroundScanSchedulerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/scanner/BackgroundScanSchedulerTest.java
@@ -650,113 +650,6 @@
assertChannels(combinedBucketChannelSet, expectedBucketChannelSet);
}
- /**
- * Add 2 background scan requests with different time intervals, but one of the setting channels
- * is totally contained in the other setting. Ensure that the requests are collapsed into a
- * common bucket with the lower time period setting.
- * This is done with NoBandChannelHelper.
- */
- @Test
- public void optimalScheduleFullyCollapsesDuplicateChannelsInBandWithNoBandChannelHelper() {
- BackgroundScanScheduler scheduler = createSchedulerWithNoBandChannelHelper();
-
- ArrayList<ScanSettings> requests = new ArrayList<>();
- requests.add(createRequest(channelsToSpec(2400, 2450), 160000, 0, 20,
- WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN));
- requests.add(createRequest(WifiScanner.WIFI_BAND_BOTH_WITH_DFS, 10000, 0, 20,
- WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN));
-
- scheduler.setMaxBuckets(2);
- scheduler.setMaxChannelsPerBucket(2);
- scheduler.updateSchedule(requests);
- WifiNative.ScanSettings schedule = scheduler.getSchedule();
-
- assertEquals("base_period_ms", 10000, schedule.base_period_ms);
- assertBuckets(schedule, 1);
-
- assertEquals("scheduled bucket", 0, scheduler.getScheduledBucket(requests.get(0)));
- assertEquals("scheduled bucket", 0, scheduler.getScheduledBucket(requests.get(1)));
-
- assertEquals("band", schedule.buckets[0].band, WifiScanner.WIFI_BAND_BOTH_WITH_DFS);
- }
-
- /**
- * Add 2 background scan requests with different time intervals, but one of the setting channels
- * is partially contained in the other setting. Ensure that the requests are partially split
- * across the lower time period bucket.
- */
- @Test
- public void optimalSchedulePartiallyCollapsesDuplicateChannelsWithNoBandChannelHelper() {
- BackgroundScanScheduler scheduler = createSchedulerWithNoBandChannelHelper();
-
- ArrayList<ScanSettings> requests = new ArrayList<>();
- requests.add(createRequest(channelsToSpec(2400, 2450), 10000, 0, 20,
- WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN));
- requests.add(createRequest(channelsToSpec(2400, 2450, 5175), 240000, 0, 20,
- WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN));
-
- scheduler.setMaxBuckets(2);
- scheduler.setMaxChannelsPerBucket(3);
- scheduler.updateSchedule(requests);
- WifiNative.ScanSettings schedule = scheduler.getSchedule();
-
- assertEquals("base_period_ms", 10000, schedule.base_period_ms);
- assertBuckets(schedule, 2);
-
- assertEquals("scheduled bucket", 0, scheduler.getScheduledBucket(requests.get(0)));
- assertEquals("scheduled bucket", 1, scheduler.getScheduledBucket(requests.get(1)));
-
- Set<Integer> expectedBucketChannelSet = new ArraySet<>();
- expectedBucketChannelSet.add(2400);
- expectedBucketChannelSet.add(2450);
- assertBucketChannels(schedule.buckets[0], expectedBucketChannelSet);
-
- expectedBucketChannelSet.clear();
- expectedBucketChannelSet.add(5175);
- assertBucketChannels(schedule.buckets[1], expectedBucketChannelSet);
- }
-
- /**
- * Add 2 background scan requests with the second scan request having channels more than the
- * max, ensure that the last bucket is split.
- */
- @Test
- public void optimalScheduleShouldSplitBucketsWithNoBandChannelHelper() {
- BackgroundScanScheduler scheduler = createSchedulerWithNoBandChannelHelper();
-
- ArrayList<ScanSettings> requests = new ArrayList<>();
- requests.add(createRequest(channelsToSpec(2400, 2450), 10000, 0, 20,
- WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN));
- requests.add(createRequest(channelsToSpec(5150, 5175, 5600, 5650), 240000, 0, 20,
- WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN));
-
- scheduler.setMaxBuckets(3);
- scheduler.setMaxChannelsPerBucket(2);
- scheduler.updateSchedule(requests);
- WifiNative.ScanSettings schedule = scheduler.getSchedule();
-
- assertEquals("base_period_ms", 10000, schedule.base_period_ms);
- assertBuckets(schedule, 3);
-
- assertEquals("scheduled bucket", 0, scheduler.getScheduledBucket(requests.get(0)));
- assertEquals("scheduled bucket", 1, scheduler.getScheduledBucket(requests.get(1)));
-
- Set<Integer> expectedBucketChannelSet = new ArraySet<>();
- expectedBucketChannelSet.add(2400);
- expectedBucketChannelSet.add(2450);
- assertBucketChannels(schedule.buckets[0], expectedBucketChannelSet);
-
- expectedBucketChannelSet.clear();
- expectedBucketChannelSet.add(5150);
- expectedBucketChannelSet.add(5175);
- assertBucketChannels(schedule.buckets[1], expectedBucketChannelSet);
-
- expectedBucketChannelSet.clear();
- expectedBucketChannelSet.add(5600);
- expectedBucketChannelSet.add(5650);
- assertBucketChannels(schedule.buckets[2], expectedBucketChannelSet);
- }
-
protected Set<Integer> getAllChannels(BucketSettings bucket) {
KnownBandsChannelCollection collection = mChannelHelper.createChannelCollection();
collection.addChannels(bucket);
@@ -930,16 +823,6 @@
+ expectedChannelSet, channelSet.containsAll(expectedChannelSet));
}
- private BackgroundScanScheduler createSchedulerWithNoBandChannelHelper() {
- NoBandChannelHelper channelHelper = new NoBandChannelHelper();
- BackgroundScanScheduler scheduler = new BackgroundScanScheduler(channelHelper);
- scheduler.setMaxBuckets(DEFAULT_MAX_BUCKETS);
- scheduler.setMaxChannelsPerBucket(DEFAULT_MAX_CHANNELS_PER_BUCKET);
- scheduler.setMaxBatch(DEFAULT_MAX_BATCH);
- scheduler.setMaxApPerScan(DEFAULT_MAX_AP_PER_SCAN);
- return scheduler;
- }
-
private static int[] getPredefinedBuckets() {
try {
Field f = BackgroundScanScheduler.class.getDeclaredField("PREDEFINED_BUCKET_PERIODS");
diff --git a/tests/wifitests/src/com/android/server/wifi/scanner/ChannelHelperTest.java b/tests/wifitests/src/com/android/server/wifi/scanner/ChannelHelperTest.java
index e2fd875..941c357 100644
--- a/tests/wifitests/src/com/android/server/wifi/scanner/ChannelHelperTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/scanner/ChannelHelperTest.java
@@ -92,6 +92,27 @@
/**
* Unit tests for
+ * {@link com.android.server.wifi.scanner.ChannelHelper#bandToString}.
+ */
+ @Test
+ public void bandToString_ShouldReturnApproapriateString() {
+ assertEquals("unspecified", ChannelHelper.bandToString(
+ WifiScanner.WIFI_BAND_UNSPECIFIED));
+ assertEquals("24Ghz", ChannelHelper.bandToString(WifiScanner.WIFI_BAND_24_GHZ));
+ assertEquals("5Ghz (no DFS)", ChannelHelper.bandToString(WifiScanner.WIFI_BAND_5_GHZ));
+ assertEquals("5Ghz (DFS only)", ChannelHelper.bandToString(
+ WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY));
+ assertEquals("5Ghz (DFS incl)", ChannelHelper.bandToString(
+ WifiScanner.WIFI_BAND_5_GHZ_WITH_DFS));
+ assertEquals("24Ghz & 5Ghz (no DFS)", ChannelHelper.bandToString(
+ WifiScanner.WIFI_BAND_BOTH));
+ assertEquals("24Ghz & 5Ghz (DFS incl)", ChannelHelper.bandToString(
+ WifiScanner.WIFI_BAND_BOTH_WITH_DFS));
+ assertEquals("invalid band", ChannelHelper.bandToString(-235342));
+ }
+
+ /**
+ * Unit tests for
* {@link com.android.server.wifi.scanner.ChannelHelper.ChannelCollection}.
*/
@SmallTest
diff --git a/tests/wifitests/src/com/android/server/wifi/scanner/NoBandChannelHelperTest.java b/tests/wifitests/src/com/android/server/wifi/scanner/NoBandChannelHelperTest.java
deleted file mode 100644
index 145b214..0000000
--- a/tests/wifitests/src/com/android/server/wifi/scanner/NoBandChannelHelperTest.java
+++ /dev/null
@@ -1,402 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wifi.scanner;
-
-import static com.android.server.wifi.ScanTestUtil.bandIs;
-import static com.android.server.wifi.ScanTestUtil.channelsAre;
-import static com.android.server.wifi.ScanTestUtil.channelsToSpec;
-import static com.android.server.wifi.ScanTestUtil.createRequest;
-
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-import android.net.wifi.WifiScanner;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import com.android.server.wifi.WifiNative;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.experimental.runners.Enclosed;
-import org.junit.runner.RunWith;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-
-/**
- * Unit tests for {@link com.android.server.wifi.scanner.NoBandChannelHelper}.
- */
-@RunWith(Enclosed.class) // WARNING: tests cannot be declared in the outer class
-public class NoBandChannelHelperTest {
- private static final int ALL_BANDS = WifiScanner.WIFI_BAND_BOTH_WITH_DFS;
-
- /**
- * Unit tests for
- * {@link com.android.server.wifi.scanner.NoBandChannelHelper.estimateScanDuration}.
- */
- @SmallTest
- public static class EstimateScanDurationTest {
- NoBandChannelHelper mChannelHelper;
-
- /**
- * Called before each test
- * Create a channel helper
- */
- @Before
- public void setUp() throws Exception {
- mChannelHelper = new NoBandChannelHelper();
- }
-
- /**
- * check a settings object with a few channels
- */
- @Test
- public void fewChannels() {
- WifiScanner.ScanSettings testSettings = createRequest(channelsToSpec(2400, 2450, 5100),
- 10000, 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
-
- assertEquals(ChannelHelper.SCAN_PERIOD_PER_CHANNEL_MS * 3,
- mChannelHelper.estimateScanDuration(testSettings));
- }
-
- /**
- * check a settings object with a band
- */
- @Test
- public void band() {
- WifiScanner.ScanSettings testSettings = createRequest(WifiScanner.WIFI_BAND_24_GHZ,
- 10000, 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
-
- assertTrue("Expected scan to take some time",
- mChannelHelper.estimateScanDuration(testSettings)
- >= ChannelHelper.SCAN_PERIOD_PER_CHANNEL_MS);
- }
- }
-
- /**
- * Unit tests for
- * {@link com.android.server.wifi.scanner.NoBandChannelHelper.getAvailableScanChannels}.
- */
- @SmallTest
- public static class GetAvailableScanChannelsTest {
- NoBandChannelHelper mChannelHelper;
-
- /**
- * Called before each test
- * Create a channel helper
- */
- @Before
- public void setUp() throws Exception {
- mChannelHelper = new NoBandChannelHelper();
- }
-
- /**
- * Test that getting the channels for each band results in the expected empty list
- */
- @Test
- public void eachBandValue() {
- for (int band = WifiScanner.WIFI_BAND_24_GHZ;
- band <= WifiScanner.WIFI_BAND_BOTH_WITH_DFS; ++band) {
- WifiScanner.ChannelSpec[] channels =
- mChannelHelper.getAvailableScanChannels(band);
- assertEquals("expected zero channels", 0, channels.length);
- }
- }
- }
-
- /**
- * Unit tests for
- * {@link com.android.server.wifi.scanner.NoBandChannelHelper.settingsContainChannel}.
- */
- @SmallTest
- public static class SettingsContainChannelTest {
- NoBandChannelHelper mChannelHelper;
-
- /**
- * Called before each test
- * Create a channel helper
- */
- @Before
- public void setUp() throws Exception {
- mChannelHelper = new NoBandChannelHelper();
- }
-
- /**
- * check a settings object with no channels
- */
- @Test
- public void emptySettings() {
- WifiScanner.ScanSettings testSettings = createRequest(channelsToSpec(),
- 10000, 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
-
- assertFalse(mChannelHelper.settingsContainChannel(testSettings, 2400));
- assertFalse(mChannelHelper.settingsContainChannel(testSettings, 5150));
- assertFalse(mChannelHelper.settingsContainChannel(testSettings, 5650));
- }
-
- /**
- * check a settings object with some channels
- */
- @Test
- public void settingsWithChannels() {
- WifiScanner.ScanSettings testSettings = createRequest(channelsToSpec(2400, 5650),
- 10000, 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
-
- assertTrue(mChannelHelper.settingsContainChannel(testSettings, 2400));
- assertFalse(mChannelHelper.settingsContainChannel(testSettings, 5150));
- assertTrue(mChannelHelper.settingsContainChannel(testSettings, 5650));
- }
-
- /**
- * check a settings object with a band specified
- */
- @Test
- public void settingsWithBand() {
- WifiScanner.ScanSettings testSettings = createRequest(WifiScanner.WIFI_BAND_24_GHZ,
- 10000, 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
-
- assertTrue(mChannelHelper.settingsContainChannel(testSettings, 2400));
- assertTrue(mChannelHelper.settingsContainChannel(testSettings, 2450));
- assertTrue(mChannelHelper.settingsContainChannel(testSettings, 5150));
- assertTrue(mChannelHelper.settingsContainChannel(testSettings, 5650));
- }
-
- /**
- * check a settings object with multiple bands specified
- */
- @Test
- public void settingsWithMultiBand() {
- WifiScanner.ScanSettings testSettings = createRequest(WifiScanner.WIFI_BAND_BOTH,
- 10000, 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
-
- assertTrue(mChannelHelper.settingsContainChannel(testSettings, 2400));
- assertTrue(mChannelHelper.settingsContainChannel(testSettings, 2450));
- assertTrue(mChannelHelper.settingsContainChannel(testSettings, 5150));
- assertTrue(mChannelHelper.settingsContainChannel(testSettings, 5650));
- }
- }
-
- /**
- * Unit tests for
- * {@link com.android.server.wifi.scanner.NoBandChannelHelper.NoBandChannelCollection}.
- */
- @SmallTest
- public static class NoBandsChannelCollectionTest {
- ChannelHelper.ChannelCollection mChannelCollection;
-
- /**
- * Called before each test
- * Create a collection to use for each test
- */
- @Before
- public void setUp() throws Exception {
- mChannelCollection = new NoBandChannelHelper().createChannelCollection();
- }
-
- /**
- * Create an empty collection
- */
- @Test
- public void empty() {
- WifiNative.BucketSettings bucketSettings = new WifiNative.BucketSettings();
- mChannelCollection.fillBucketSettings(bucketSettings, Integer.MAX_VALUE);
- assertThat(bucketSettings, channelsAre());
-
- assertEquals(Collections.<Integer>emptySet(),
- mChannelCollection.getScanFreqs());
-
- assertTrue(mChannelCollection.isEmpty());
- assertFalse(mChannelCollection.containsChannel(2400));
- assertFalse(mChannelCollection.isAllChannels());
- }
-
- /**
- * Add something to a collection and then clear it and make sure nothing is in it
- */
- @Test
- public void clear() {
- mChannelCollection.addBand(WifiScanner.WIFI_BAND_24_GHZ);
- mChannelCollection.clear();
-
- WifiNative.BucketSettings bucketSettings = new WifiNative.BucketSettings();
- mChannelCollection.fillBucketSettings(bucketSettings, Integer.MAX_VALUE);
- assertThat(bucketSettings, channelsAre());
-
- assertEquals(Collections.<Integer>emptySet(),
- mChannelCollection.getScanFreqs());
-
- assertTrue(mChannelCollection.isEmpty());
- assertFalse(mChannelCollection.containsChannel(2400));
- assertFalse(mChannelCollection.isAllChannels());
- }
-
- /**
- * Add a single band to the collection
- */
- @Test
- public void addBand() {
- mChannelCollection.addBand(WifiScanner.WIFI_BAND_24_GHZ);
-
- WifiNative.BucketSettings bucketSettings = new WifiNative.BucketSettings();
- mChannelCollection.fillBucketSettings(bucketSettings, Integer.MAX_VALUE);
- assertThat(bucketSettings, bandIs(ALL_BANDS));
-
- assertNull(mChannelCollection.getScanFreqs());
-
- assertFalse(mChannelCollection.isEmpty());
- assertTrue(mChannelCollection.containsChannel(2400));
- assertTrue(mChannelCollection.containsChannel(5150));
- assertTrue(mChannelCollection.isAllChannels());
- }
-
- /**
- * Add a single channel to the collection
- */
- @Test
- public void addChannel_single() {
- mChannelCollection.addChannel(2400);
-
- WifiNative.BucketSettings bucketSettings = new WifiNative.BucketSettings();
- mChannelCollection.fillBucketSettings(bucketSettings, Integer.MAX_VALUE);
- assertThat(bucketSettings, channelsAre(2400));
-
- assertEquals(new HashSet<Integer>(Arrays.asList(2400)),
- mChannelCollection.getScanFreqs());
-
- assertFalse(mChannelCollection.isEmpty());
- assertTrue(mChannelCollection.containsChannel(2400));
- assertFalse(mChannelCollection.containsChannel(5150));
- assertFalse(mChannelCollection.isAllChannels());
- }
-
- /**
- * Add a multiple channels to the collection
- */
- @Test
- public void addChannel_multiple() {
- mChannelCollection.addChannel(2400);
- mChannelCollection.addChannel(2450);
-
- WifiNative.BucketSettings bucketSettings = new WifiNative.BucketSettings();
- mChannelCollection.fillBucketSettings(bucketSettings, Integer.MAX_VALUE);
- assertThat(bucketSettings, channelsAre(2400, 2450));
-
- assertEquals(new HashSet<Integer>(Arrays.asList(2400, 2450)),
- mChannelCollection.getScanFreqs());
-
- assertFalse(mChannelCollection.isEmpty());
- assertTrue(mChannelCollection.containsChannel(2400));
- assertFalse(mChannelCollection.containsChannel(5150));
- assertFalse(mChannelCollection.isAllChannels());
- }
-
- /**
- * Add a band and channel that is on that band
- */
- @Test
- public void addChannel_and_addBand_sameBand() {
- mChannelCollection.addBand(WifiScanner.WIFI_BAND_24_GHZ);
- mChannelCollection.addChannel(2400);
-
- WifiNative.BucketSettings bucketSettings = new WifiNative.BucketSettings();
- mChannelCollection.fillBucketSettings(bucketSettings, Integer.MAX_VALUE);
- assertThat(bucketSettings, bandIs(ALL_BANDS));
-
- assertNull(mChannelCollection.getScanFreqs());
-
- assertFalse(mChannelCollection.isEmpty());
- assertTrue(mChannelCollection.containsChannel(2400));
- assertTrue(mChannelCollection.containsChannel(5150));
- assertTrue(mChannelCollection.isAllChannels());
- }
-
- /**
- * Add a band and channel that is not that band
- */
- @Test
- public void addChannel_and_addBand_withDifferentBandChannel() {
- mChannelCollection.addBand(WifiScanner.WIFI_BAND_24_GHZ);
- mChannelCollection.addChannel(5150);
-
- WifiNative.BucketSettings bucketSettings = new WifiNative.BucketSettings();
- mChannelCollection.fillBucketSettings(bucketSettings, Integer.MAX_VALUE);
- assertThat(bucketSettings, bandIs(ALL_BANDS));
-
- assertNull(mChannelCollection.getScanFreqs());
-
- assertFalse(mChannelCollection.isEmpty());
- assertTrue(mChannelCollection.containsChannel(2400));
- assertTrue(mChannelCollection.containsChannel(5150));
- assertTrue(mChannelCollection.isAllChannels());
- }
-
- /**
- * Add a band that should contain all channels
- */
- @Test
- public void addChannel_and_addBand_all() {
- mChannelCollection.addBand(WifiScanner.WIFI_BAND_BOTH_WITH_DFS);
- mChannelCollection.addChannel(5150);
-
- WifiNative.BucketSettings bucketSettings = new WifiNative.BucketSettings();
- mChannelCollection.fillBucketSettings(bucketSettings, Integer.MAX_VALUE);
- assertThat(bucketSettings, bandIs(WifiScanner.WIFI_BAND_BOTH_WITH_DFS));
-
- assertNull(mChannelCollection.getScanFreqs());
-
- assertFalse(mChannelCollection.isEmpty());
- assertTrue(mChannelCollection.containsChannel(2400));
- assertTrue(mChannelCollection.containsChannel(5150));
- assertTrue(mChannelCollection.containsChannel(5600));
- assertTrue(mChannelCollection.isAllChannels());
- }
-
- /**
- * Add enough channels on a single band that the max channels is exceeded
- */
- @Test
- public void addChannel_exceedMaxChannels() {
- mChannelCollection.addChannel(5600);
- mChannelCollection.addChannel(5650);
- mChannelCollection.addChannel(5660);
-
- WifiNative.BucketSettings bucketSettings = new WifiNative.BucketSettings();
- mChannelCollection.fillBucketSettings(bucketSettings, 2);
- assertThat(bucketSettings, bandIs(ALL_BANDS));
- assertFalse(mChannelCollection.isAllChannels()); // can't determine from just channels
- }
-
- /**
- * Add enough channels across multiple bands that the max channels is exceeded
- */
- @Test
- public void addChannel_exceedMaxChannelsOnMultipleBands() {
- mChannelCollection.addChannel(2400);
- mChannelCollection.addChannel(2450);
- mChannelCollection.addChannel(5150);
-
- WifiNative.BucketSettings bucketSettings = new WifiNative.BucketSettings();
- mChannelCollection.fillBucketSettings(bucketSettings, 2);
- assertThat(bucketSettings, bandIs(ALL_BANDS));
- assertFalse(mChannelCollection.isAllChannels()); // can't determine from just channels
- }
- }
-}
diff --git a/tests/wifitests/src/com/android/server/wifi/scanner/WifiScanningServiceTest.java b/tests/wifitests/src/com/android/server/wifi/scanner/WifiScanningServiceTest.java
index 01835cd..4ffc66d 100644
--- a/tests/wifitests/src/com/android/server/wifi/scanner/WifiScanningServiceTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/scanner/WifiScanningServiceTest.java
@@ -74,7 +74,6 @@
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
import java.util.List;
import java.util.regex.Pattern;
@@ -1722,21 +1721,6 @@
return Pair.create(requestSettings, nativeSettings);
}
- private Pair<WifiScanner.ScanSettings, WifiNative.ScanSettings> createScanSettingsForSwPno()
- throws Exception {
- Pair<WifiScanner.ScanSettings, WifiNative.ScanSettings> settingsPair =
- createScanSettingsForHwPno();
-
- WifiScanner.ScanSettings requestSettings = settingsPair.first;
- WifiNative.ScanSettings nativeSettings = settingsPair.second;
- // reportEvents field is overridden for SW PNO
- for (int i = 0; i < nativeSettings.buckets.length; i++) {
- nativeSettings.buckets[i].report_events = WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN
- | WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT;
- }
- return Pair.create(requestSettings, nativeSettings);
- }
-
private Pair<WifiScanner.PnoSettings, WifiNative.PnoSettings> createPnoSettings(
ScanResults results)
throws Exception {
@@ -1832,10 +1816,9 @@
mLooper.dispatchAll();
}
- private void expectHwPnoScanWithNoBackgroundScan(InOrder order, Handler handler, int requestId,
+ private void expectHwPnoScan(InOrder order, Handler handler, int requestId,
WifiNative.PnoSettings nativeSettings, ScanResults results) {
when(mWifiScannerImpl.isHwPnoSupported(anyBoolean())).thenReturn(true);
- when(mWifiScannerImpl.shouldScheduleBackgroundScanForHwPno()).thenReturn(false);
when(mWifiScannerImpl.setHwPnoList(any(WifiNative.PnoSettings.class),
any(WifiNative.PnoEventHandler.class))).thenReturn(true);
@@ -1846,47 +1829,6 @@
mLooper.dispatchAll();
}
- private void expectHwPnoScanWithBackgroundScan(InOrder order, Handler handler, int requestId,
- WifiNative.ScanSettings nativeScanSettings,
- WifiNative.PnoSettings nativePnoSettings, ScanResults results) {
- when(mWifiScannerImpl.isHwPnoSupported(anyBoolean())).thenReturn(true);
- when(mWifiScannerImpl.shouldScheduleBackgroundScanForHwPno()).thenReturn(true);
-
- when(mWifiScannerImpl.setHwPnoList(any(WifiNative.PnoSettings.class),
- any(WifiNative.PnoEventHandler.class))).thenReturn(true);
- when(mWifiScannerImpl.startBatchedScan(any(WifiNative.ScanSettings.class),
- any(WifiNative.ScanEventHandler.class))).thenReturn(true);
- mLooper.dispatchAll();
- WifiNative.PnoEventHandler eventHandler = verifyHwPno(order, nativePnoSettings);
- verifySuccessfulResponse(order, handler, requestId);
- verifyStartBackgroundScan(order, nativeScanSettings);
- eventHandler.onPnoNetworkFound(results.getRawScanResults());
- mLooper.dispatchAll();
- }
-
- private void expectHwPnoScanWithBackgroundScanWithNoIE(InOrder order, Handler handler,
- int requestId, WifiNative.ScanSettings nativeBackgroundScanSettings,
- WifiNative.ScanSettings nativeSingleScanSettings,
- WifiNative.PnoSettings nativePnoSettings, ScanResults results) {
- when(mWifiScannerImpl.startSingleScan(any(WifiNative.ScanSettings.class),
- any(WifiNative.ScanEventHandler.class))).thenReturn(true);
-
- expectHwPnoScanWithBackgroundScan(order, handler, requestId, nativeBackgroundScanSettings,
- nativePnoSettings, results);
- WifiNative.ScanEventHandler eventHandler =
- verifyStartSingleScan(order, nativeSingleScanSettings);
- when(mWifiScannerImpl.getLatestSingleScanResults()).thenReturn(results.getScanData());
- eventHandler.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
- mLooper.dispatchAll();
- }
- private void expectSwPnoScan(InOrder order, WifiNative.ScanSettings nativeScanSettings,
- ScanResults results) {
- when(mWifiScannerImpl.isHwPnoSupported(anyBoolean())).thenReturn(false);
- when(mWifiScannerImpl.shouldScheduleBackgroundScanForHwPno()).thenReturn(true);
-
- expectSuccessfulBackgroundScan(order, nativeScanSettings, results);
- }
-
/**
* Tests wificond PNO scan when the PNO scan results contain IE info. This ensures that the
* PNO scan results are plumbed back to the client as a PNO network found event.
@@ -1907,88 +1849,7 @@
createPnoSettings(scanResults);
sendPnoScanRequest(controlChannel, requestId, scanSettings.first, pnoSettings.first);
- expectHwPnoScanWithNoBackgroundScan(order, handler, requestId, pnoSettings.second,
- scanResults);
- verifyPnoNetworkFoundReceived(order, handler, requestId, scanResults.getRawScanResults());
- }
-
- /**
- * Tests Hal ePNO scan when the PNO scan results contain IE info. This ensures that the
- * PNO scan results are plumbed back to the client as a PNO network found event.
- */
- @Test
- public void testSuccessfulHwPnoScanWithBackgroundScan() throws Exception {
- startServiceAndLoadDriver();
- mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog);
- Handler handler = mock(Handler.class);
- BidirectionalAsyncChannel controlChannel = connectChannel(handler);
- InOrder order = inOrder(handler, mWifiScannerImpl);
- int requestId = 12;
-
- ScanResults scanResults = createScanResultsForPno();
- Pair<WifiScanner.ScanSettings, WifiNative.ScanSettings> scanSettings =
- createScanSettingsForHwPno();
- Pair<WifiScanner.PnoSettings, WifiNative.PnoSettings> pnoSettings =
- createPnoSettings(scanResults);
-
- sendPnoScanRequest(controlChannel, requestId, scanSettings.first, pnoSettings.first);
- expectHwPnoScanWithBackgroundScan(order, handler, requestId, scanSettings.second,
- pnoSettings.second, scanResults);
- verifyPnoNetworkFoundReceived(order, handler, requestId, scanResults.getRawScanResults());
- }
-
- /**
- * Tests Hal ePNO scan when the PNO scan results don't contain IE info. This ensures that the
- * single scan results are plumbed back to the client as a PNO network found event.
- */
- @Test
- public void testSuccessfulHwPnoScanWithBackgroundScanWithNoIE() throws Exception {
- startServiceAndLoadDriver();
- mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog);
- Handler handler = mock(Handler.class);
- BidirectionalAsyncChannel controlChannel = connectChannel(handler);
- InOrder order = inOrder(handler, mWifiScannerImpl);
- int requestId = 12;
-
- ScanResults scanResults = createScanResultsForPnoWithNoIE();
- Pair<WifiScanner.ScanSettings, WifiNative.ScanSettings> scanSettings =
- createScanSettingsForHwPno();
- Pair<WifiScanner.PnoSettings, WifiNative.PnoSettings> pnoSettings =
- createPnoSettings(scanResults);
-
- sendPnoScanRequest(controlChannel, requestId, scanSettings.first, pnoSettings.first);
- expectHwPnoScanWithBackgroundScanWithNoIE(order, handler, requestId, scanSettings.second,
- computeSingleScanNativeSettings(scanSettings.first), pnoSettings.second,
- scanResults);
-
- ArrayList<ScanResult> sortScanList =
- new ArrayList<ScanResult>(Arrays.asList(scanResults.getRawScanResults()));
- Collections.sort(sortScanList, WifiScannerImpl.SCAN_RESULT_SORT_COMPARATOR);
- verifyPnoNetworkFoundReceived(order, handler, requestId,
- sortScanList.toArray(new ScanResult[sortScanList.size()]));
- }
-
- /**
- * Tests SW PNO scan. This ensures that the background scan results are plumbed back to the
- * client as a PNO network found event.
- */
- @Test
- public void testSuccessfulSwPnoScan() throws Exception {
- startServiceAndLoadDriver();
- mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog);
- Handler handler = mock(Handler.class);
- BidirectionalAsyncChannel controlChannel = connectChannel(handler);
- InOrder order = inOrder(handler, mWifiScannerImpl);
- int requestId = 12;
-
- ScanResults scanResults = createScanResultsForPno();
- Pair<WifiScanner.ScanSettings, WifiNative.ScanSettings> scanSettings =
- createScanSettingsForSwPno();
- Pair<WifiScanner.PnoSettings, WifiNative.PnoSettings> pnoSettings =
- createPnoSettings(scanResults);
-
- sendPnoScanRequest(controlChannel, requestId, scanSettings.first, pnoSettings.first);
- expectSwPnoScan(order, scanSettings.second, scanResults);
+ expectHwPnoScan(order, handler, requestId, pnoSettings.second, scanResults);
verifyPnoNetworkFoundReceived(order, handler, requestId, scanResults.getRawScanResults());
}
diff --git a/tests/wifitests/src/com/android/server/wifi/scanner/WificondPnoScannerTest.java b/tests/wifitests/src/com/android/server/wifi/scanner/WificondPnoScannerTest.java
index 974cf66..73ea143 100644
--- a/tests/wifitests/src/com/android/server/wifi/scanner/WificondPnoScannerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/scanner/WificondPnoScannerTest.java
@@ -18,6 +18,7 @@
import static com.android.server.wifi.ScanTestUtil.NativeScanSettingsBuilder;
import static com.android.server.wifi.ScanTestUtil.assertScanDataEquals;
+import static com.android.server.wifi.ScanTestUtil.setupMockChannels;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
@@ -71,6 +72,11 @@
mWifiMonitor = new MockWifiMonitor();
mResources = new MockResources();
+ setupMockChannels(mWifiNative,
+ new int[]{2400, 2450},
+ new int[]{5150, 5175},
+ new int[]{5600, 5650});
+
when(mWifiNative.getInterfaceName()).thenReturn("a_test_interface_name");
when(mContext.getSystemService(Context.ALARM_SERVICE))
.thenReturn(mAlarmManager.getAlarmManager());
@@ -108,8 +114,8 @@
WifiNative.PnoEventHandler pnoEventHandler = mock(WifiNative.PnoEventHandler.class);
WifiNative.PnoSettings pnoSettings = createDummyPnoSettings(false);
WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
- WifiNative.ScanSettings settings = createDummyScanSettings();
- ScanResults scanResults = createDummyScanResults(true);
+ WifiNative.ScanSettings settings = createDummyScanSettings(false);
+ ScanResults scanResults = createDummyScanResults(false);
InOrder order = inOrder(eventHandler, mWifiNative);
// Start PNO scan
@@ -134,36 +140,6 @@
}
/**
- * Verify that the SW disconnected PNO scan triggers a background scan and invokes the
- * background scan callbacks when scan results are received.
- */
- @Test
- public void startSwDisconnectedPnoScan() {
- createScannerWithSwPnoScanSupport();
- doSuccessfulSwPnoScanTest(false);
- }
-
- /**
- * Verify that the HW connected PNO scan triggers a background scan and invokes the
- * background scan callbacks when scan results are received.
- */
- @Test
- public void startHwConnectedPnoScan() {
- createScannerWithHwPnoScanSupport();
- doSuccessfulSwPnoScanTest(true);
- }
-
- /**
- * Verify that the SW connected PNO scan triggers a background scan and invokes the
- * background scan callbacks when scan results are received.
- */
- @Test
- public void startSwConnectedPnoScan() {
- createScannerWithSwPnoScanSupport();
- doSuccessfulSwPnoScanTest(true);
- }
-
- /**
* Verify that the HW PNO delayed failure cleans up the scan settings cleanly.
* 1. Start Hw PNO.
* 2. Start Single Scan which should pause PNO scan.
@@ -177,8 +153,8 @@
WifiNative.PnoEventHandler pnoEventHandler = mock(WifiNative.PnoEventHandler.class);
WifiNative.PnoSettings pnoSettings = createDummyPnoSettings(false);
WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
- WifiNative.ScanSettings settings = createDummyScanSettings();
- ScanResults scanResults = createDummyScanResults(true);
+ WifiNative.ScanSettings settings = createDummyScanSettings(false);
+ ScanResults scanResults = createDummyScanResults(false);
InOrder order = inOrder(eventHandler, mWifiNative);
// Start PNO scan
@@ -325,33 +301,10 @@
order.verify(mWifiNative, never()).stopPnoScan();
}
- private void doSuccessfulSwPnoScanTest(boolean isConnectedPno) {
- WifiNative.PnoEventHandler pnoEventHandler = mock(WifiNative.PnoEventHandler.class);
- WifiNative.PnoSettings pnoSettings = createDummyPnoSettings(isConnectedPno);
- WifiNative.ScanEventHandler scanEventHandler = mock(WifiNative.ScanEventHandler.class);
- WifiNative.ScanSettings scanSettings = createDummyScanSettings();
- ScanResults scanResults = createDummyScanResults(false);
-
- InOrder order = inOrder(scanEventHandler, mWifiNative);
-
- // Start PNO scan
- startSuccessfulPnoScan(scanSettings, pnoSettings, scanEventHandler, pnoEventHandler);
-
- expectSuccessfulSwPnoScan(order, scanEventHandler, scanResults);
-
- verifyNoMoreInteractions(pnoEventHandler);
- }
-
private void createScannerWithHwPnoScanSupport() {
mResources.setBoolean(R.bool.config_wifi_background_scan_support, true);
mScanner = new WificondScannerImpl(mContext, mWifiNative, mWifiMonitor,
- mLooper.getLooper(), mClock);
- }
-
- private void createScannerWithSwPnoScanSupport() {
- mResources.setBoolean(R.bool.config_wifi_background_scan_support, false);
- mScanner = new WificondScannerImpl(mContext, mWifiNative, mWifiMonitor,
- mLooper.getLooper(), mClock);
+ new WificondChannelHelper(mWifiNative), mLooper.getLooper(), mClock);
}
private WifiNative.PnoNetwork createDummyPnoNetwork(String ssid) {
@@ -369,12 +322,15 @@
return pnoSettings;
}
- private WifiNative.ScanSettings createDummyScanSettings() {
+ private WifiNative.ScanSettings createDummyScanSettings(boolean allChannelsScanned) {
WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
.withBasePeriod(10000)
.withMaxApPerScan(10)
- .addBucketWithBand(10000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
- WifiScanner.WIFI_BAND_24_GHZ)
+ .addBucketWithBand(
+ 10000,
+ WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
+ allChannelsScanned
+ ? WifiScanner.WIFI_BAND_BOTH_WITH_DFS : WifiScanner.WIFI_BAND_24_GHZ)
.build();
return settings;
}
@@ -393,14 +349,7 @@
when(mWifiNative.startPnoScan(any(WifiNative.PnoSettings.class))).thenReturn(true);
when(mWifiNative.stopPnoScan()).thenReturn(true);
- if (mScanner.isHwPnoSupported(pnoSettings.isConnected)) {
- // This should happen only for HW PNO scan
- assertTrue(mScanner.setHwPnoList(pnoSettings, pnoEventHandler));
- } else {
- // This should happen only for SW PNO scan
- assertTrue(mScanner.startBatchedScan(scanSettings, scanEventHandler));
-
- }
+ assertTrue(mScanner.setHwPnoList(pnoSettings, pnoEventHandler));
}
private Set<Integer> expectedBandScanFreqs(int band) {
@@ -463,33 +412,4 @@
assertScanDataEquals(scanResults.getScanData(), mScanner.getLatestSingleScanResults());
}
- /**
- * Verify that the SW PNO scan was successfully started. This could either be disconnected
- * or connected PNO.
- * This is basically ensuring that the background scan runs successfully and returns the
- * expected result.
- */
- private void expectSuccessfulSwPnoScan(InOrder order,
- WifiNative.ScanEventHandler eventHandler, ScanResults scanResults) {
-
- // Verify scan started
- order.verify(mWifiNative).scan(any(), any(Set.class));
-
- // Make sure that HW PNO scan was not started
- verify(mWifiNative, never()).startPnoScan(any(WifiNative.PnoSettings.class));
-
- // Setup scan results
- when(mWifiNative.getScanResults()).thenReturn(scanResults.getScanDetailArrayList());
- when(mWifiNative.getPnoScanResults()).thenReturn(scanResults.getScanDetailArrayList());
-
- // Notify scan has finished
- mWifiMonitor.sendMessage(mWifiNative.getInterfaceName(), WifiMonitor.SCAN_RESULTS_EVENT);
- assertEquals("dispatch message after results event", 1, mLooper.dispatchAll());
-
- // Verify background scan results delivered
- order.verify(eventHandler).onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
- WifiScanner.ScanData[] scanData = mScanner.getLatestBatchedScanResults(true);
- WifiScanner.ScanData lastScanData = scanData[scanData.length - 1];
- assertScanDataEquals(scanResults.getScanData(), lastScanData);
- }
}
diff --git a/tests/wifitests/src/com/android/server/wifi/scanner/WificondScannerTest.java b/tests/wifitests/src/com/android/server/wifi/scanner/WificondScannerTest.java
index d337cf1..3657e50 100644
--- a/tests/wifitests/src/com/android/server/wifi/scanner/WificondScannerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/scanner/WificondScannerTest.java
@@ -17,31 +17,23 @@
package com.android.server.wifi.scanner;
import static com.android.server.wifi.ScanTestUtil.NativeScanSettingsBuilder;
-import static com.android.server.wifi.ScanTestUtil.assertScanDatasEquals;
-import static com.android.server.wifi.ScanTestUtil.createFreqSet;
+import static com.android.server.wifi.ScanTestUtil.setupMockChannels;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
-import android.net.wifi.ScanResult;
import android.net.wifi.WifiScanner;
-import android.net.wifi.WifiSsid;
import android.test.suitebuilder.annotation.SmallTest;
-import com.android.server.wifi.ScanDetail;
-import com.android.server.wifi.ScanResults;
-import com.android.server.wifi.WifiMonitor;
import com.android.server.wifi.WifiNative;
import com.android.server.wifi.scanner.ChannelHelper.ChannelCollection;
import org.junit.Before;
import org.junit.Test;
-import org.mockito.InOrder;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.io.StringWriter;
-import java.util.ArrayList;
import java.util.Set;
import java.util.regex.Pattern;
@@ -53,8 +45,12 @@
@Before
public void setup() throws Exception {
+ setupMockChannels(mWifiNative,
+ new int[]{2400, 2450},
+ new int[]{5150, 5175},
+ new int[]{5600, 5650});
mScanner = new WificondScannerImpl(mContext, mWifiNative, mWifiMonitor,
- mLooper.getLooper(), mClock);
+ new WificondChannelHelper(mWifiNative), mLooper.getLooper(), mClock);
}
/**
@@ -90,506 +86,6 @@
verify(eventHandler).onScanStatus(WifiNative.WIFI_SCAN_FAILED);
}
- @Test
- public void backgroundScanSuccessSingleBucket() {
- WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
- .withBasePeriod(10000)
- .withMaxApPerScan(10)
- .addBucketWithBand(10000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
- WifiScanner.WIFI_BAND_24_GHZ)
- .build();
-
- ScanPeriod[] expectedPeriods = new ScanPeriod[] {
- new ScanPeriod(ScanPeriod.ReportType.RESULT,
- ScanResults.create(0, 2400),
- expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ)),
- new ScanPeriod(ScanPeriod.ReportType.RESULT,
- ScanResults.create(1, 2450),
- expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ))
- };
-
- doSuccessfulTest(settings, expectedPeriods);
- }
-
- @Test
- public void backgroundScanMaxApExceeded() {
- WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
- .withBasePeriod(10000)
- .withMaxApPerScan(2)
- .addBucketWithBand(10000,
- WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN
- | WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT,
- WifiScanner.WIFI_BAND_24_GHZ)
- .build();
-
- ScanPeriod[] expectedPeriods = new ScanPeriod[] {
- new ScanPeriod(ScanPeriod.ReportType.FULL_AND_RESULT,
- ScanResults.createOverflowing(0, 2,
- new ScanDetail(WifiSsid.createFromAsciiEncoded("TEST AP 1"),
- "00:00:00:00:00:00", "", -70, 2450, Long.MAX_VALUE, 0),
- new ScanDetail(WifiSsid.createFromAsciiEncoded("TEST AP 2"),
- "AA:BB:CC:DD:EE:FF", "", -66, 2400, Long.MAX_VALUE, 0),
- new ScanDetail(WifiSsid.createFromAsciiEncoded("TEST AP 3"),
- "00:00:00:00:00:00", "", -80, 2450, Long.MAX_VALUE, 0),
- new ScanDetail(WifiSsid.createFromAsciiEncoded("TEST AP 4"),
- "AA:BB:CC:11:22:33", "", -65, 2450, Long.MAX_VALUE, 0)),
- expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ))
- };
-
- doSuccessfulTest(settings, expectedPeriods);
- }
-
- @Test
- public void backgroundScanSuccessWithFullScanResults() {
- WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
- .withBasePeriod(10000)
- .withMaxApPerScan(10)
- .addBucketWithBand(10000,
- WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN
- | WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT,
- WifiScanner.WIFI_BAND_24_GHZ)
- .build();
-
- ScanPeriod[] expectedPeriods = new ScanPeriod[] {
- new ScanPeriod(ScanPeriod.ReportType.FULL_AND_RESULT,
- ScanResults.create(0, 2400, 2450, 2400, 2400),
- expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ)),
- new ScanPeriod(ScanPeriod.ReportType.FULL_AND_RESULT,
- ScanResults.create(1, 2450, 2400, 2450, 2400),
- expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ))
- };
-
- doSuccessfulTest(settings, expectedPeriods);
- }
-
- @Test
- public void backgroundScanSuccessWithMixedFullResultsAndNot() {
- WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
- .withBasePeriod(10000)
- .withMaxApPerScan(10)
- .addBucketWithBand(10000,
- WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
- WifiScanner.WIFI_BAND_24_GHZ)
- .addBucketWithBand(20000,
- WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN
- | WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT,
- WifiScanner.WIFI_BAND_5_GHZ)
- .build();
-
- ScanPeriod[] expectedPeriods = new ScanPeriod[] {
- new ScanPeriod(ScanPeriod.ReportType.FULL_AND_RESULT,
- ScanResults.create(0, 2400, 2450, 2400, 5175),
- expectedBandScanFreqs(WifiScanner.WIFI_BAND_BOTH)),
- new ScanPeriod(ScanPeriod.ReportType.RESULT,
- ScanResults.create(1, 2450, 2400, 2450, 2400),
- expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ)),
- new ScanPeriod(ScanPeriod.ReportType.FULL_AND_RESULT,
- ScanResults.create(2, 2450, 2400, 2450, 5150),
- expectedBandScanFreqs(WifiScanner.WIFI_BAND_BOTH))
- };
-
- doSuccessfulTest(settings, expectedPeriods);
- }
-
- @Test
- public void backgroundScanNoBatch() {
- WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
- .withBasePeriod(10000)
- .withMaxApPerScan(10)
- .addBucketWithBand(10000,
- WifiScanner.REPORT_EVENT_NO_BATCH,
- WifiScanner.WIFI_BAND_24_GHZ)
- .build();
-
- ScanPeriod[] expectedPeriods = new ScanPeriod[] {
- new ScanPeriod(ScanPeriod.ReportType.NONE,
- ScanResults.create(0, 2400, 2400, 2400),
- expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ)),
- new ScanPeriod(ScanPeriod.ReportType.NONE,
- ScanResults.create(1, 2400, 2400, 2450),
- expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ)),
- new ScanPeriod(ScanPeriod.ReportType.NONE,
- ScanResults.create(2, 2400, 2450, 2400),
- expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ))
- };
-
- doSuccessfulTest(settings, expectedPeriods);
- }
-
- @Test
- public void backgroundScanBatch() {
- WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
- .withBasePeriod(10000)
- .withMaxApPerScan(10)
- .withMaxScansToCache(3)
- .addBucketWithBand(10000,
- WifiScanner.REPORT_EVENT_AFTER_BUFFER_FULL,
- WifiScanner.WIFI_BAND_24_GHZ)
- .build();
-
- ScanResults[] periodResults = new ScanResults[] {
- ScanResults.create(0, 2400, 2400, 2400),
- ScanResults.create(1, 2400, 2400, 2400, 2400),
- ScanResults.create(2, 2450),
- ScanResults.create(3, 2400, 2400),
- ScanResults.create(4, 2400, 2450),
- ScanResults.create(5, 2450)
- };
-
- ScanPeriod[] expectedPeriods = new ScanPeriod[] {
- new ScanPeriod(ScanPeriod.ReportType.NONE,
- periodResults[0],
- expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ)),
- new ScanPeriod(ScanPeriod.ReportType.NONE,
- periodResults[1],
- expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ)),
- new ScanPeriod(ScanPeriod.ReportType.RESULT,
- new ScanResults[] {
- periodResults[0],
- periodResults[1],
- periodResults[2]
- },
- expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ)),
- new ScanPeriod(ScanPeriod.ReportType.NONE,
- periodResults[3],
- expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ)),
- new ScanPeriod(ScanPeriod.ReportType.NONE,
- periodResults[4],
- expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ)),
- new ScanPeriod(ScanPeriod.ReportType.RESULT,
- new ScanResults[] {
- periodResults[3],
- periodResults[4],
- periodResults[5]
- },
- expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ))
- };
-
- doSuccessfulTest(settings, expectedPeriods);
- }
-
- @Test
- public void backgroundScanSuccessWithMultipleBuckets() {
- WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
- .withBasePeriod(10000)
- .withMaxApPerScan(10)
- .addBucketWithBand(10000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
- WifiScanner.WIFI_BAND_24_GHZ)
- .addBucketWithBand(30000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
- WifiScanner.WIFI_BAND_BOTH)
- .addBucketWithChannels(20000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
- 5650)
- .build();
-
- ScanPeriod[] expectedPeriods = new ScanPeriod[] {
- new ScanPeriod(ScanPeriod.ReportType.RESULT,
- ScanResults.create(0, 2400, 5175),
- expectedBandAndChannelScanFreqs(WifiScanner.WIFI_BAND_BOTH, 5650)),
- new ScanPeriod(ScanPeriod.ReportType.RESULT,
- ScanResults.create(1, 2400),
- expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ)),
- new ScanPeriod(ScanPeriod.ReportType.RESULT,
- ScanResults.create(2, 2450, 5650),
- expectedBandAndChannelScanFreqs(WifiScanner.WIFI_BAND_24_GHZ, 5650)),
- new ScanPeriod(ScanPeriod.ReportType.RESULT,
- ScanResults.create(3, 2450, 5175),
- expectedBandScanFreqs(WifiScanner.WIFI_BAND_BOTH)),
- new ScanPeriod(ScanPeriod.ReportType.RESULT,
- ScanResults.create(4, new int[0]),
- expectedBandAndChannelScanFreqs(WifiScanner.WIFI_BAND_24_GHZ, 5650)),
- new ScanPeriod(ScanPeriod.ReportType.RESULT,
- ScanResults.create(5, 2400, 2400, 2400, 2450),
- expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ)),
- new ScanPeriod(ScanPeriod.ReportType.RESULT,
- ScanResults.create(6, 5150, 5650, 5650),
- expectedBandAndChannelScanFreqs(WifiScanner.WIFI_BAND_BOTH, 5650))
- };
-
- doSuccessfulTest(settings, expectedPeriods);
- }
-
- @Test
- public void backgroundScanSuccessWithMultipleBucketsWhereAPeriodDoesNotRequireAScan() {
- WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
- .withBasePeriod(10000)
- .withMaxApPerScan(10)
- .addBucketWithBand(30000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
- WifiScanner.WIFI_BAND_BOTH)
- .addBucketWithChannels(20000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
- 5650)
- .build();
-
- // expected scan frequencies
- ScanPeriod[] expectedPeriods = new ScanPeriod[] {
- new ScanPeriod(ScanPeriod.ReportType.RESULT,
- ScanResults.create(0, 2400, 5175),
- expectedBandAndChannelScanFreqs(WifiScanner.WIFI_BAND_BOTH, 5650)),
- null,
- new ScanPeriod(ScanPeriod.ReportType.RESULT,
- ScanResults.create(1, 5650),
- createFreqSet(5650)),
- new ScanPeriod(ScanPeriod.ReportType.RESULT,
- ScanResults.create(2, 2450, 5175),
- expectedBandScanFreqs(WifiScanner.WIFI_BAND_BOTH)),
- new ScanPeriod(ScanPeriod.ReportType.RESULT,
- ScanResults.create(3, 5650, 5650, 5650),
- createFreqSet(5650)),
- null,
- new ScanPeriod(ScanPeriod.ReportType.RESULT,
- ScanResults.create(4, 2400, 2400, 2400, 2450),
- expectedBandAndChannelScanFreqs(WifiScanner.WIFI_BAND_BOTH, 5650))
- };
-
- doSuccessfulTest(settings, expectedPeriods);
- }
-
- @Test
- public void backgroundScanStartFailed() {
- WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
- WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
- .withBasePeriod(10000)
- .withMaxApPerScan(10)
- .addBucketWithBand(10000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
- WifiScanner.WIFI_BAND_24_GHZ)
- .build();
-
- InOrder order = inOrder(eventHandler, mWifiNative);
-
- // All scans fail
- when(mWifiNative.scan(any(), any(Set.class))).thenReturn(false);
-
- // Start scan
- mScanner.startBatchedScan(settings, eventHandler);
-
- assertBackgroundPeriodAlarmPending();
-
- expectFailedScanStart(order, eventHandler,
- expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ));
-
- // Fire alarm to start next scan
- dispatchBackgroundPeriodAlarm();
-
- assertBackgroundPeriodAlarmPending();
-
- expectFailedScanStart(order, eventHandler,
- expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ));
-
- verifyNoMoreInteractions(eventHandler);
- }
-
-
- @Test
- public void backgroundScanEventFailed() {
- WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
- WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
- .withBasePeriod(10000)
- .withMaxApPerScan(10)
- .addBucketWithBand(10000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
- WifiScanner.WIFI_BAND_24_GHZ)
- .build();
-
- InOrder order = inOrder(eventHandler, mWifiNative);
-
- // All scan starts succeed
- when(mWifiNative.scan(any(), any(Set.class))).thenReturn(true);
-
- // Start scan
- mScanner.startBatchedScan(settings, eventHandler);
-
- assertBackgroundPeriodAlarmPending();
-
- expectFailedEventScan(order, eventHandler,
- expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ));
-
- // Fire alarm to start next scan
- dispatchBackgroundPeriodAlarm();
-
- assertBackgroundPeriodAlarmPending();
-
- expectFailedEventScan(order, eventHandler,
- expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ));
-
- verifyNoMoreInteractions(eventHandler);
- }
-
- /**
- * Run a scan and then pause after the first scan completes, but before the next one starts
- * Then resume the scan
- */
- @Test
- public void pauseWhileWaitingToStartNextScanAndResumeScan() {
- WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
- WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
- .withBasePeriod(10000)
- .withMaxApPerScan(10)
- .addBucketWithBand(10000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
- WifiScanner.WIFI_BAND_24_GHZ)
- .build();
-
- ScanPeriod[] expectedPeriods = new ScanPeriod[] {
- new ScanPeriod(ScanPeriod.ReportType.RESULT,
- ScanResults.create(0, 2400, 2450, 2450),
- expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ)),
- new ScanPeriod(ScanPeriod.ReportType.RESULT,
- ScanResults.create(1, 2400),
- expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ))
- };
-
- InOrder order = inOrder(eventHandler, mWifiNative);
-
- // All scan starts succeed
- when(mWifiNative.scan(any(), any(Set.class))).thenReturn(true);
-
- // Start scan
- mScanner.startBatchedScan(settings, eventHandler);
-
- assertBackgroundPeriodAlarmPending();
-
- expectSuccessfulBackgroundScan(order, eventHandler, expectedPeriods[0], 0);
-
- assertBackgroundPeriodAlarmPending();
-
- mScanner.pauseBatchedScan();
-
- // onPause callback (previous results were flushed)
- order.verify(eventHandler).onScanPaused(new WifiScanner.ScanData[0]);
-
- assertBackgroundPeriodAlarmNotPending();
-
- mScanner.restartBatchedScan();
-
- // onRestarted callback
- order.verify(eventHandler).onScanRestarted();
-
- expectSuccessfulBackgroundScan(order, eventHandler, expectedPeriods[1], 1);
-
- verifyNoMoreInteractions(eventHandler);
- }
-
- /**
- * Run a scan and then pause while the first scan is running
- * Then resume the scan
- */
- @Test
- public void pauseWhileScanningAndResumeScan() {
- WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
- WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
- .withBasePeriod(10000)
- .withMaxApPerScan(10)
- .addBucketWithBand(10000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
- WifiScanner.WIFI_BAND_24_GHZ)
- .build();
-
- ScanPeriod[] expectedPeriods = new ScanPeriod[] {
- new ScanPeriod(ScanPeriod.ReportType.RESULT,
- ScanResults.create(0, 2400, 2450, 2450),
- expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ)),
- new ScanPeriod(ScanPeriod.ReportType.RESULT,
- ScanResults.create(1, 2400),
- expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ))
- };
-
- InOrder order = inOrder(eventHandler, mWifiNative);
-
- // All scan starts succeed
- when(mWifiNative.scan(any(), any(Set.class))).thenReturn(true);
-
- // Start scan
- mScanner.startBatchedScan(settings, eventHandler);
-
- assertBackgroundPeriodAlarmPending();
-
- order.verify(mWifiNative).scan(eq(expectedPeriods[0].getScanFreqs()), any(Set.class));
-
- mScanner.pauseBatchedScan();
-
- // onPause callback (no pending results)
- order.verify(eventHandler).onScanPaused(new WifiScanner.ScanData[0]);
-
- assertBackgroundPeriodAlarmNotPending();
-
- // Setup scan results
- when(mWifiNative.getScanResults()).thenReturn(expectedPeriods[0]
- .getResultsToBeDelivered()[0].getScanDetailArrayList());
-
- // Notify scan has finished
- mWifiMonitor.sendMessage(mWifiNative.getInterfaceName(), WifiMonitor.SCAN_RESULTS_EVENT);
- assertEquals("dispatch message after results event", 1, mLooper.dispatchAll());
-
- // listener should not be notified
-
- mScanner.restartBatchedScan();
-
- // onRestarted callback
- order.verify(eventHandler).onScanRestarted();
-
- expectSuccessfulBackgroundScan(order, eventHandler, expectedPeriods[1], 1);
-
- verifyNoMoreInteractions(eventHandler);
- }
-
-
- /**
- * Run a scan and then pause after the first scan completes, but before the next one starts
- * Then schedule a new scan while still paused
- */
- @Test
- public void pauseWhileWaitingToStartNextScanAndStartNewScan() {
- WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
- WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
- .withBasePeriod(10000)
- .withMaxApPerScan(10)
- .addBucketWithBand(10000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
- WifiScanner.WIFI_BAND_24_GHZ)
- .build();
-
- WifiNative.ScanSettings settings2 = new NativeScanSettingsBuilder()
- .withBasePeriod(10000)
- .withMaxApPerScan(10)
- .addBucketWithBand(10000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
- WifiScanner.WIFI_BAND_5_GHZ)
- .build();
-
- ScanPeriod[] expectedPeriods = new ScanPeriod[] {
- new ScanPeriod(ScanPeriod.ReportType.RESULT,
- ScanResults.create(0, 2400, 2450, 2450),
- expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ))
- };
-
- ScanPeriod[] expectedPeriods2 = new ScanPeriod[] {
- new ScanPeriod(ScanPeriod.ReportType.RESULT,
- ScanResults.create(1, 5150, 5175, 5175),
- expectedBandScanFreqs(WifiScanner.WIFI_BAND_5_GHZ)),
- };
-
- InOrder order = inOrder(eventHandler, mWifiNative);
-
- // All scan starts succeed
- when(mWifiNative.scan(any(), any(Set.class))).thenReturn(true);
-
- // Start scan
- mScanner.startBatchedScan(settings, eventHandler);
-
- assertBackgroundPeriodAlarmPending();
-
- expectSuccessfulBackgroundScan(order, eventHandler, expectedPeriods[0], 0);
-
- assertBackgroundPeriodAlarmPending();
-
- mScanner.pauseBatchedScan();
-
- // onPause callback (previous results were flushed)
- order.verify(eventHandler).onScanPaused(new WifiScanner.ScanData[0]);
-
- assertBackgroundPeriodAlarmNotPending();
-
- // Start new scan
- mScanner.startBatchedScan(settings2, eventHandler);
-
- expectSuccessfulBackgroundScan(order, eventHandler, expectedPeriods2[0], 0);
-
- verifyNoMoreInteractions(eventHandler);
- }
/**
* Test that dump() of WificondScannerImpl dumps native scan results.
@@ -613,173 +109,4 @@
return stringWriter.toString();
}
- /**
- * Run a test with the given settings where all native scans succeed
- * This will execute expectedPeriods.length scan periods by first
- * starting the scan settings and then dispatching the scan period alarm to start the
- * next scan.
- */
- private void doSuccessfulTest(WifiNative.ScanSettings settings, ScanPeriod[] expectedPeriods) {
- WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
-
- InOrder order = inOrder(eventHandler, mWifiNative);
-
- // All scans succeed
- when(mWifiNative.scan(any(), any(Set.class))).thenReturn(true);
-
- // Start scan
- mScanner.startBatchedScan(settings, eventHandler);
-
- for (int i = 0; i < expectedPeriods.length; ++i) {
- ScanPeriod period = expectedPeriods[i];
- assertBackgroundPeriodAlarmPending();
- if (period != null) { // scan should be scheduled
- expectSuccessfulBackgroundScan(order, eventHandler, expectedPeriods[i], i);
- }
- if (i < expectedPeriods.length - 1) {
- dispatchBackgroundPeriodAlarm();
- }
- }
-
- verifyNoMoreInteractions(eventHandler);
- }
-
- /**
- * Verify the state after a scan was started either through startBatchedScan or
- * dispatching the period alarm.
- */
- private void expectSuccessfulBackgroundScan(InOrder order,
- WifiNative.ScanEventHandler eventHandler, ScanPeriod period, int periodId) {
- WifiScanner.ScanData[] scanDatas = null;
- ArrayList<ScanDetail> nativeResults = null;
- ScanResult[] fullResults = null;
- if (period.getResultsToBeDelivered() != null) {
- ScanResults lastPeriodResults = period.getResultsToBeDelivered()
- [period.getResultsToBeDelivered().length - 1];
- nativeResults = lastPeriodResults.getScanDetailArrayList();
- if (period.expectResults()) {
- scanDatas =
- new WifiScanner.ScanData[period.getResultsToBeDelivered().length];
- for (int j = 0; j < scanDatas.length; ++j) {
- scanDatas[j] = period.getResultsToBeDelivered()[j].getScanData();
- }
- }
- if (period.expectFullResults()) {
- fullResults = lastPeriodResults.getRawScanResults();
- }
- }
- expectSuccessfulBackgroundScan(order, eventHandler, period.getScanFreqs(),
- nativeResults, scanDatas, fullResults, periodId);
- }
-
- /**
- * Verify the state after a scan was started either through startBatchedScan or
- * dispatching the period alarm.
- */
- private void expectSuccessfulBackgroundScan(InOrder order,
- WifiNative.ScanEventHandler eventHandler, Set<Integer> scanFreqs,
- ArrayList<ScanDetail> nativeResults,
- WifiScanner.ScanData[] expectedScanResults,
- ScanResult[] fullResults, int periodId) {
- // Verify scan started
- order.verify(mWifiNative).scan(eq(scanFreqs), any(Set.class));
-
- // Setup scan results
- when(mWifiNative.getScanResults()).thenReturn(nativeResults);
-
- // Notify scan has finished
- mWifiMonitor.sendMessage(mWifiNative.getInterfaceName(), WifiMonitor.SCAN_RESULTS_EVENT);
- assertEquals("dispatch message after results event", 1, mLooper.dispatchAll());
-
- if (fullResults != null) {
- for (ScanResult result : fullResults) {
- order.verify(eventHandler).onFullScanResult(eq(result), eq(0));
- }
- }
-
- if (expectedScanResults != null) {
- // Verify scan results delivered
- order.verify(eventHandler).onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
- assertScanDatasEquals("period[" + periodId + "].", expectedScanResults,
- mScanner.getLatestBatchedScanResults(true));
- }
- }
-
- private void expectFailedScanStart(InOrder order, WifiNative.ScanEventHandler eventHandler,
- Set<Integer> scanFreqs) {
- // Verify scan started
- order.verify(mWifiNative).scan(eq(scanFreqs), any(Set.class));
- }
-
- private void expectFailedEventScan(InOrder order, WifiNative.ScanEventHandler eventHandler,
- Set<Integer> scanFreqs) {
- // Verify scan started
- order.verify(mWifiNative).scan(eq(scanFreqs), any(Set.class));
-
- // Notify scan has failed
- mWifiMonitor.sendMessage(mWifiNative.getInterfaceName(), WifiMonitor.SCAN_FAILED_EVENT);
- assertEquals("dispatch message after results event", 1, mLooper.dispatchAll());
-
- // TODO: verify failure event
- }
-
- private void assertBackgroundPeriodAlarmPending() {
- assertTrue("background period alarm not pending",
- mAlarmManager.isPending(WificondScannerImpl.BACKGROUND_PERIOD_ALARM_TAG));
- }
-
- private void assertBackgroundPeriodAlarmNotPending() {
- assertFalse("background period alarm is pending",
- mAlarmManager.isPending(WificondScannerImpl.BACKGROUND_PERIOD_ALARM_TAG));
- }
-
- private void dispatchBackgroundPeriodAlarm() {
- assertTrue("dispatch background period alarm",
- mAlarmManager.dispatch(WificondScannerImpl.BACKGROUND_PERIOD_ALARM_TAG));
- mLooper.dispatchAll();
- }
-
- private static class ScanPeriod {
- enum ReportType {
- NONE(false, false),
- RESULT(true, false),
- FULL_AND_RESULT(true, true),
- FULL(false, true);
-
- public final boolean result;
- public final boolean full;
- ReportType(boolean result, boolean full) {
- this.result = result;
- this.full = full;
- }
- };
- private final ReportType mReportType;
- private final ScanResults[] mDeliveredResults;
- private final Set<Integer> mRequestedFreqs;
-
- ScanPeriod(ReportType reportType, ScanResults deliveredResult,
- Set<Integer> requestedFreqs) {
- this(reportType, new ScanResults[] {deliveredResult}, requestedFreqs);
- }
-
- ScanPeriod(ReportType reportType, ScanResults[] deliveredResults,
- Set<Integer> requestedFreqs) {
- mReportType = reportType;
- mDeliveredResults = deliveredResults;
- mRequestedFreqs = requestedFreqs;
- }
-
- public boolean expectResults() {
- return mReportType.result;
- }
- public boolean expectFullResults() {
- return mReportType.full;
- }
- public final ScanResults[] getResultsToBeDelivered() {
- return mDeliveredResults;
- }
- public Set<Integer> getScanFreqs() {
- return mRequestedFreqs;
- }
- }
}
diff --git a/tests/wifitests/src/com/android/server/wifi/util/ApConfigUtilTest.java b/tests/wifitests/src/com/android/server/wifi/util/ApConfigUtilTest.java
index a9d3fea..92551a8 100644
--- a/tests/wifitests/src/com/android/server/wifi/util/ApConfigUtilTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/util/ApConfigUtilTest.java
@@ -235,28 +235,8 @@
when(mWifiNative.isHalStarted()).thenReturn(true);
when(mWifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ))
.thenReturn(null);
- when(mWifiNative.isGetChannelsForBandSupported()).thenReturn(true);
assertEquals(ApConfigUtil.ERROR_NO_CHANNEL,
ApConfigUtil.updateApChannelConfig(
mWifiNative, TEST_COUNTRY_CODE, mAllowed2GChannels, config));
}
-
- /**
- * Verify updateApChannelConfig will use the default band and channel when
- * GetChannelsForBand API is not supported by HAL.
- */
- @Test
- public void updateApChannelConfigWithoutChannelsForBandSupported() throws Exception {
- WifiConfiguration config = new WifiConfiguration();
- config.apBand = WifiConfiguration.AP_BAND_5GHZ;
- when(mWifiNative.isHalStarted()).thenReturn(true);
- when(mWifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ))
- .thenReturn(null);
- when(mWifiNative.isGetChannelsForBandSupported()).thenReturn(false);
- assertEquals(ApConfigUtil.SUCCESS,
- ApConfigUtil.updateApChannelConfig(
- mWifiNative, TEST_COUNTRY_CODE, mAllowed2GChannels, config));
- assertEquals(ApConfigUtil.DEFAULT_AP_BAND, config.apBand);
- assertEquals(ApConfigUtil.DEFAULT_AP_CHANNEL, config.apChannel);
- }
}
diff --git a/tests/wifitests/src/com/android/server/wifi/util/InformationElementUtilTest.java b/tests/wifitests/src/com/android/server/wifi/util/InformationElementUtilTest.java
index b9a8c31..86b394f 100644
--- a/tests/wifitests/src/com/android/server/wifi/util/InformationElementUtilTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/util/InformationElementUtilTest.java
@@ -727,12 +727,12 @@
/**
* Verify that the expected Interworking information element is parsed and retrieved from the
- * list of IEs.
+ * list of IEs. Uses an IE w/o the optional Venue Info.
*
* @throws Exception
*/
@Test
- public void getInterworkingElementIE() throws Exception {
+ public void getInterworkingElementNoVenueIE() throws Exception {
InformationElement ie = new InformationElement();
ie.id = InformationElement.EID_INTERWORKING;
/**
@@ -753,4 +753,34 @@
assertEquals(NetworkDetail.Ant.Private, interworking.ant);
assertEquals(0x112233445566L, interworking.hessid);
}
+
+ /**
+ * Verify that the expected Interworking information element is parsed and retrieved from the
+ * list of IEs. Uses an IE with the optional Venue Info.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void getInterworkingElementWithVenueIE() throws Exception {
+ InformationElement ie = new InformationElement();
+ ie.id = InformationElement.EID_INTERWORKING;
+ /**
+ * Interworking Format:
+ * | Access Network Option | Venue Info (optional) | HESSID (optional) |
+ * 1 2 6
+ *
+ * Access Network Option Format:
+ *
+ * B0 B3 B4 B5 B6 B7
+ * | Access Network Type | Internet | ASRA | ESR | UESA |
+ */
+ ie.bytes = new byte[]{(byte) 0x10, (byte) 0xAA, (byte) 0xBB, (byte) 0x11, (byte) 0x22,
+ (byte) 0x33, (byte) 0x44, (byte) 0x55, (byte) 0x66};
+ InformationElementUtil.Interworking interworking =
+ InformationElementUtil.getInterworkingIE(new InformationElement[] {ie});
+ assertTrue(interworking.internet);
+ assertEquals(NetworkDetail.Ant.Private, interworking.ant);
+ assertEquals(0x112233445566L, interworking.hessid);
+ }
+
}
diff --git a/tests/wifitests/src/com/android/server/wifi/util/KalmanFilterTest.java b/tests/wifitests/src/com/android/server/wifi/util/KalmanFilterTest.java
new file mode 100644
index 0000000..5e06e70
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/util/KalmanFilterTest.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wifi.util;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+import java.util.Random;
+
+/**
+ * Unit tests for {@link com.android.server.wifi.util.KalmanFilter}.
+ */
+public class KalmanFilterTest {
+ /**
+ * Test that constructor works
+ */
+ @Test
+ public void testConstructor() throws Exception {
+ KalmanFilter kf = new KalmanFilter();
+ assertNotNull(kf);
+ }
+
+ /**
+ * Sets up a Kalman filter to behave as as a phase-locked loop
+ * <p>
+ * Set up a 2-D model that generates sinusoidal output at a fixed frequency; the state
+ * transformation is just a rotation by a fixed angle, and the output matrix projects oen
+ * of the dimensions.
+ */
+ private KalmanFilter initializePll(double stepSizeRadians,
+ double modelStandardDeviation,
+ double measurementStandardDeviation) {
+ KalmanFilter kf = new KalmanFilter();
+ double cos = Math.cos(stepSizeRadians);
+ double sin = Math.sin(stepSizeRadians);
+ kf.mF = new Matrix(2, new double[]{
+ cos, sin,
+ -sin, cos});
+ double modelVariance = modelStandardDeviation * modelStandardDeviation;
+ kf.mQ = new Matrix(2, new double[]{
+ modelVariance, 0.0,
+ 0.0, modelVariance});
+ kf.mH = new Matrix(2, new double[]{1.0, 0.0});
+ double measurementVariance = measurementStandardDeviation * measurementStandardDeviation;
+ kf.mR = new Matrix(1, new double[]{measurementVariance});
+ double initialAPosterioriVariance = 10000.0;
+ kf.mP = new Matrix(2, new double[]{
+ initialAPosterioriVariance, 0.0,
+ 0.0, initialAPosterioriVariance});
+ kf.mx = new Matrix(2, 1);
+ return kf;
+ }
+
+ private double mAmplitude = 10.0;
+ private double mStepSizeRadians = Math.PI / 17.01;
+ private int mTransitionPoint = 300;
+
+ /**
+ * Generates the ideal signal at time step i.
+ * <p>
+ * Sinusoid, with an abrupt phase shift thrown in to test transient response
+ */
+ private double idealSignal(int i) {
+ double phi = mStepSizeRadians * i;
+ if (i > mTransitionPoint) {
+ phi = phi + Math.PI * .75;
+ }
+ return mAmplitude * Math.sin(phi);
+ }
+
+ private double mNoiseAmplitude = 3.0;
+
+ private int mSteps = 500;
+ private int mSeed = 271828;
+
+ /**
+ * Test that using the phase locked loop Kalman filter results in a residual that is
+ * a lot smaller than the noise in the signal.
+ */
+ @Test
+ public void testPhaseLockedLoop() throws Exception {
+ Random random = new Random(mSeed);
+ double modelStandardDeviation = 0.5;
+ double [] noise = new double[mSteps];
+ for (int i = 0; i < mSteps; i++) {
+ noise[i] = random.nextGaussian() * mNoiseAmplitude;
+ }
+ double [] filtered = new double[mSteps];
+ double [] residual = new double[mSteps];
+ KalmanFilter kf = initializePll(mStepSizeRadians, modelStandardDeviation, mNoiseAmplitude);
+ for (int i = 0; i < mSteps; i++) {
+ kf.predict();
+ kf.update(new Matrix(1, new double[] {idealSignal(i) + noise[i]}));
+ filtered[i] = kf.mx.get(0, 0);
+ residual[i] = filtered[i] - idealSignal(i);
+ }
+ double sum = 0.0;
+ double sumSquares = 0.0;
+ double n = 0.0;
+ for (int i = 0; i < mSteps; i++) {
+ if (i < 5 || (i > mTransitionPoint && i < mTransitionPoint + 20)) continue;
+ sum += residual[i];
+ sumSquares += residual[i] * residual[i];
+ n += 1.0;
+ }
+ double mean = sum / n;
+ double variance = (sumSquares - sum * sum) / (n * n);
+ assertTrue(mean < 0.1);
+ assertTrue(variance < 1.5);
+ assertNotNull(kf.toString());
+ }
+
+ /**
+ * Test that the toString method works even if the matrices have not been set.
+ */
+ @Test
+ public void testToStrinWithNullsInside() throws Exception {
+ assertNotNull(new KalmanFilter().toString());
+ }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/util/MatrixTest.java b/tests/wifitests/src/com/android/server/wifi/util/MatrixTest.java
index bfa1071..f347f3d 100644
--- a/tests/wifitests/src/com/android/server/wifi/util/MatrixTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/util/MatrixTest.java
@@ -17,9 +17,13 @@
package com.android.server.wifi.util;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.fail;
import org.junit.Test;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.Random;
/**
@@ -67,7 +71,18 @@
}
/**
- * Test multiplication.
+ * Test scalar multiplication.
+ */
+ @Test
+ public void testScalarMultiplication() throws Exception {
+ Matrix m1 = new Matrix(2, new double[]{1, 2, 3, 4});
+ double x = 1001;
+ Matrix m2 = new Matrix(2, new double[]{x * 1, x * 2, x * 3, x * 4});
+ assertEquals(m2, m1.times(x));
+ }
+
+ /**
+ * Test matrix multiplication.
*/
@Test
public void testMultiplication() throws Exception {
@@ -94,18 +109,75 @@
}
/**
+ * Generates a random permuation matrix
+ */
+ public Matrix generatePermutationMatrix(int size, Random random) {
+ Matrix matrix = new Matrix(size, size);
+ ArrayList<Integer> j = new ArrayList(size);
+ for (int i = 0; i < size; i++) {
+ j.add(i);
+ }
+ Collections.shuffle(j, random);
+ for (int i = 0; i < size; i++) {
+ matrix.put(i, j.get(i), 1.0);
+ }
+ return matrix;
+ }
+
+ /**
+ * Test that inverting a random permutaion matrix works
+ */
+ @Test
+ public void testInverseOfPermutation() throws Exception {
+ int size = 20;
+ Matrix m1 = generatePermutationMatrix(size, new Random(132));
+ Matrix m2 = m1.inverse();
+ Matrix m3 = m1.transpose();
+ assertEquals(m3, m2);
+ }
+
+ /**
* Test that attempting to invert a singular matrix throws an exception.
* @throws Exception
*/
- @Test(expected = ArithmeticException.class)
+ @Test
public void testSingularity() throws Exception {
Matrix m1 = new Matrix(3, new double[]{10, 1, -1, 0, 0, 0, 0, 0, 0});
- Matrix m2 = m1.inverse();
+ try {
+ m1.inverse();
+ fail("Expected ArithmeticException");
+ } catch (ArithmeticException e) {
+ return;
+ }
+ }
+
+ /**
+ * Test multiplication by a transpose
+ */
+ @Test
+ public void testMultiplicationByTranspose() throws Exception {
+ Matrix m1 = new Matrix(2, new double[]{1, 2, 3, 4, 5, 6});
+ Matrix m2 = new Matrix(2, new double[]{1, 2, 3, 4, 5, 6, 7, 8});
+ assertEquals(m1.dot(m2.transpose()), m1.dotTranspose(m2));
+ }
+
+ /**
+ * Test that exception is thrown for non-conformable dotTranspose
+ */
+ @Test
+ public void testMultiplicationByBadlyShapedTranspose() throws Exception {
+ Matrix m1 = new Matrix(2, new double[]{1, 2, 3, 4, 5, 6});
+ Matrix m2 = m1.transpose();
+ try {
+ m1.dotTranspose(m2);
+ fail("Expected IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ }
}
/**
* Test that a copy is equal to the original, and that hash codes match,
- * and that string versions match.
+ * and that string versions match; exercise equals in various ways.
*/
@Test
public void testCopy() throws Exception {
@@ -114,9 +186,16 @@
for (int i = 0; i < m1.mem.length; i++) {
m1.mem[i] = random.nextDouble();
}
+ assertEquals(m1, m1);
Matrix m2 = new Matrix(m1);
assertEquals(m1, m2);
assertEquals(m1.hashCode(), m2.hashCode());
assertEquals(m1.toString(), m2.toString());
+ m2.put(2, 2, 2.0); // guaranteed change, because nextDouble() is between 0 and 1.
+ assertNotEquals(m1, m2);
+ assertNotEquals(m1, m1.transpose());
+ assertNotEquals(m1.toString(), m2.toString());
+ assertNotEquals(m1, null);
+ assertNotEquals(m1, "a");
}
}
diff --git a/tests/wifitests/src/com/android/server/wifi/util/WifiPermissionsUtilTest.java b/tests/wifitests/src/com/android/server/wifi/util/WifiPermissionsUtilTest.java
index 7f5a66d..308e267 100644
--- a/tests/wifitests/src/com/android/server/wifi/util/WifiPermissionsUtilTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/util/WifiPermissionsUtilTest.java
@@ -19,7 +19,6 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doAnswer;
@@ -28,15 +27,12 @@
import android.Manifest;
import android.app.AppOpsManager;
-import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.net.NetworkScoreManager;
-import android.net.NetworkScorerAppData;
-import android.net.wifi.WifiConfiguration;
import android.os.Build;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -45,7 +41,6 @@
import com.android.server.wifi.BinderUtil;
import com.android.server.wifi.FakeWifiLog;
-import com.android.server.wifi.FrameworkFacade;
import com.android.server.wifi.WifiInjector;
import com.android.server.wifi.WifiSettingsStore;
@@ -77,10 +72,8 @@
@Mock private UserManager mMockUserManager;
@Mock private WifiSettingsStore mMockWifiSettingsStore;
@Mock private ContentResolver mMockContentResolver;
- @Mock private NetworkScoreManager mMockNetworkScoreManager;
- @Mock private WifiInjector mMockWifiInjector;
- @Mock private FrameworkFacade mMockFrameworkFacade;
- @Mock private WifiConfiguration mMockWifiConfig;
+ @Mock private NetworkScoreManager mNetworkScoreManager;
+ @Mock private WifiInjector mWifiInjector;
@Spy private FakeWifiLog mWifiLog;
private static final String TEST_PACKAGE_NAME = "com.google.somePackage";
@@ -108,10 +101,6 @@
private boolean mActiveNwScorer;
private Answer<Integer> mReturnPermission;
private HashMap<String, Integer> mPermissionsList = new HashMap<String, Integer>();
- private String mUseOpenWifiPackage;
- private NetworkScorerAppData mNetworkScorerAppData;
- private boolean mGetActiveScorerThrowsSecurityException;
- private boolean mConfigIsOpen;
/**
* Set up Mockito tests
@@ -135,8 +124,8 @@
mUid = MANAGED_PROFILE_UID; // do not really care about this value
setupTestCase();
WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
- mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
- mMockWifiInjector);
+ mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
+ mWifiInjector);
when(mMockPermissionsWrapper.getOverrideWifiConfigPermission(anyInt()))
.thenReturn(PackageManager.PERMISSION_GRANTED);
assertTrue(codeUnderTest.checkConfigOverridePermission(mUid));
@@ -150,8 +139,8 @@
mUid = OTHER_USER_UID; // do not really care about this value
setupTestCase();
WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
- mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
- mMockWifiInjector);
+ mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
+ mWifiInjector);
when(mMockPermissionsWrapper.getOverrideWifiConfigPermission(anyInt()))
.thenReturn(PackageManager.PERMISSION_DENIED);
assertFalse(codeUnderTest.checkConfigOverridePermission(mUid));
@@ -165,8 +154,8 @@
mUid = OTHER_USER_UID; // do not really care about this value
setupTestCase();
WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
- mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
- mMockWifiInjector);
+ mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
+ mWifiInjector);
doThrow(new RemoteException("Failed to check permissions for " + mUid))
.when(mMockPermissionsWrapper).getOverrideWifiConfigPermission(mUid);
assertFalse(codeUnderTest.checkConfigOverridePermission(mUid));
@@ -190,8 +179,8 @@
mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
setupTestCase();
WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
- mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
- mMockWifiInjector);
+ mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
+ mWifiInjector);
try {
output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion);
} catch (SecurityException e) {
@@ -218,8 +207,8 @@
mMockUserInfo.id = mCallingUser;
setupTestCase();
WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
- mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
- mMockWifiInjector);
+ mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
+ mWifiInjector);
try {
output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion);
} catch (SecurityException e) {
@@ -241,8 +230,8 @@
mPermissionsList.put(mMacAddressPermission, mUid);
setupTestCase();
WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
- mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
- mMockWifiInjector);
+ mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
+ mWifiInjector);
try {
output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion);
} catch (SecurityException e) {
@@ -270,8 +259,8 @@
mPermissionsList.put(mInteractAcrossUsersFullPermission, mUid);
setupTestCase();
WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
- mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
- mMockWifiInjector);
+ mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
+ mWifiInjector);
try {
output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion);
} catch (SecurityException e) {
@@ -297,8 +286,8 @@
mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED;
setupTestCase();
WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
- mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
- mMockWifiInjector);
+ mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
+ mWifiInjector);
try {
output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion);
} catch (SecurityException e) {
@@ -323,8 +312,8 @@
mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
setupTestCase();
WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
- mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
- mMockWifiInjector);
+ mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
+ mWifiInjector);
try {
output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion);
} catch (SecurityException e) {
@@ -334,354 +323,6 @@
}
/**
- * Test case setting: Package is valid because it matches the USE_OPEN_WIFI_PACKAGE.
- * User is current
- * The current config is for an open network.
- * Validate result is true
- */
- @Test
- public void testCanAccessFullConnectionInfo_PackageIsUseOpenWifiPackage() throws Exception {
- final boolean output;
- mThrowSecurityException = false;
- mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
- mUseOpenWifiPackage = TEST_PACKAGE_NAME;
- ComponentName useOpenWifiComponent = new ComponentName(TEST_PACKAGE_NAME, "TestClass");
- mNetworkScorerAppData = new NetworkScorerAppData(0 /*packageUid*/,
- null /*recommendationServiceComp*/, null /*recommendationServiceLabel*/,
- useOpenWifiComponent, null /*networkAvailableNotificationChannelId*/);
- setupTestCase();
- WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
- mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
- mMockWifiInjector);
-
- output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME,
- mUid, mTargetVersion);
-
- assertEquals(true, output);
- }
-
- /**
- * Test case setting: Package is valid because the caller has access to scan results.
- * Location mode is ON
- * User is current
- * The current config is not for an open network.
- * Validate result is true
- */
- @Test
- public void testCanAccessFullConnectionInfo_HasAccessToScanResults() throws Exception {
- final boolean output;
- mThrowSecurityException = false;
- mMockApplInfo.targetSdkVersion = Build.VERSION_CODES.GINGERBREAD;
- mLocationModeSetting = Settings.Secure.LOCATION_MODE_HIGH_ACCURACY;
- mCoarseLocationPermission = PackageManager.PERMISSION_GRANTED;
- mAllowCoarseLocationApps = AppOpsManager.MODE_ALLOWED;
- mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED;
- mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
- mConfigIsOpen = false;
-
- setupTestCase();
- WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
- mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
- mMockWifiInjector);
-
- output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME,
- mUid, mTargetVersion);
-
- assertEquals(true, output);
- }
-
- /**
- * Test case setting: Package is valid because it matches the USE_OPEN_WIFI_PACKAGE.
- * User or profile is not current but the uid has
- * permission to INTERACT_ACROSS_USERS_FULL
- * The current config is for an open network.
- * Validate result is true
- */
- @Test
- public void testCanAccessFullConnectionInfo_UserNotCurrentButHasInteractAcrossUsers()
- throws Exception {
- final boolean output;
- mThrowSecurityException = false;
- mUid = MANAGED_PROFILE_UID;
- mPermissionsList.put(mInteractAcrossUsersFullPermission, mUid);
- mUseOpenWifiPackage = TEST_PACKAGE_NAME;
- ComponentName useOpenWifiComponent = new ComponentName(TEST_PACKAGE_NAME, "TestClass");
- mNetworkScorerAppData = new NetworkScorerAppData(0 /*packageUid*/,
- null /*recommendationServiceComp*/, null /*recommendationServiceLabel*/,
- useOpenWifiComponent, null /*networkAvailableNotificationChannelId*/);
- setupTestCase();
- WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
- mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
- mMockWifiInjector);
-
- output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME,
- mUid, mTargetVersion);
-
- assertEquals(true, output);
- }
-
- /**
- * Test case setting: Package is valid because it matches the USE_OPEN_WIFI_PACKAGE.
- * User or profile is NOT current
- * INTERACT_ACROSS_USERS_FULL NOT granted
- * The current config is for an open network.
- * Validate result is false
- */
- @Test
- public void testCanAccessFullConnectionInfo_UserNotCurrentNoInteractAcrossUsers()
- throws Exception {
- final boolean output;
- mThrowSecurityException = false;
- mUid = MANAGED_PROFILE_UID;
- mUseOpenWifiPackage = TEST_PACKAGE_NAME;
- setupTestCase();
- WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
- mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
- mMockWifiInjector);
-
- output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME,
- mUid, mTargetVersion);
-
- assertEquals(false, output);
- }
-
- /**
- * Test case setting: Package is valid because it matches the USE_OPEN_WIFI_PACKAGE.
- * User is current
- * The current config is NULL.
- * Validate result is false
- */
- @Test
- public void testCanAccessFullConnectionInfo_WiFiConfigIsNull() throws Exception {
- final boolean output;
- mThrowSecurityException = false;
- mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
- mUseOpenWifiPackage = TEST_PACKAGE_NAME;
- ComponentName useOpenWifiComponent = new ComponentName(TEST_PACKAGE_NAME, "TestClass");
- mNetworkScorerAppData = new NetworkScorerAppData(0 /*packageUid*/,
- null /*recommendationServiceComp*/, null /*recommendationServiceLabel*/,
- useOpenWifiComponent, null /*networkAvailableNotificationChannelId*/);
- setupTestCase();
- WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
- mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
- mMockWifiInjector);
-
- output = codeUnderTest.canAccessFullConnectionInfo(null /*config*/, TEST_PACKAGE_NAME,
- mUid, mTargetVersion);
-
- assertEquals(false, output);
- }
-
- /**
- * Test case setting: Package is valid because it matches the USE_OPEN_WIFI_PACKAGE.
- * User is current
- * The current config is not for an open network.
- * Validate result is false
- */
- @Test
- public void testCanAccessFullConnectionInfo_WiFiConfigIsNotOpen() throws Exception {
- final boolean output;
- mThrowSecurityException = false;
- mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
- mUseOpenWifiPackage = TEST_PACKAGE_NAME;
- ComponentName useOpenWifiComponent = new ComponentName(TEST_PACKAGE_NAME, "TestClass");
- mNetworkScorerAppData = new NetworkScorerAppData(0 /*packageUid*/,
- null /*recommendationServiceComp*/, null /*recommendationServiceLabel*/,
- useOpenWifiComponent, null /*networkAvailableNotificationChannelId*/);
- mConfigIsOpen = false;
- setupTestCase();
- WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
- mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
- mMockWifiInjector);
-
- output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME,
- mUid, mTargetVersion);
-
- assertEquals(false, output);
- }
-
- /**
- * Test case setting: Package is valid because it matches the USE_OPEN_WIFI_PACKAGE.
- * User is current
- * The current config is for an open network.
- * There is no active scorer
- * Validate result is false
- */
- @Test
- public void testCanAccessFullConnectionInfo_UseOpenWifiPackageIsSetButNoActiveScorer()
- throws Exception {
- final boolean output;
- mThrowSecurityException = false;
- mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
- mUseOpenWifiPackage = TEST_PACKAGE_NAME;
- mNetworkScorerAppData = null; // getActiveScorer() will return null
- setupTestCase();
- WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
- mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
- mMockWifiInjector);
-
- output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME,
- mUid, mTargetVersion);
-
- assertEquals(false, output);
- }
-
- /**
- * Test case setting: Package is valid because it matches the USE_OPEN_WIFI_PACKAGE.
- * User is current
- * The current config is for an open network.
- * The scorer is active but the useOpenWiFi component name doesn't match
- * the provided package.
- * Validate result is false
- */
- @Test
- public void testCanAccessFullConnectionInfo_MismatchBetweenUseOpenWifiPackages()
- throws Exception {
- final boolean output;
- mThrowSecurityException = false;
- mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
- mUseOpenWifiPackage = TEST_PACKAGE_NAME;
- ComponentName useOpenWifiComponent =
- new ComponentName(mUseOpenWifiPackage + ".nomatch", "TestClass");
- mNetworkScorerAppData = new NetworkScorerAppData(0 /*packageUid*/,
- null /*recommendationServiceComp*/, null /*recommendationServiceLabel*/,
- useOpenWifiComponent, null /*networkAvailableNotificationChannelId*/);
- setupTestCase();
- WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
- mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
- mMockWifiInjector);
-
- output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME,
- mUid, mTargetVersion);
-
- assertEquals(false, output);
- }
-
- /**
- * Test case setting: Package is valid because it matches the USE_OPEN_WIFI_PACKAGE.
- * User is current
- * The current config is for an open network.
- * The scorer is active but the useOpenWiFi component name is null.
- * Validate result is false
- */
- @Test
- public void testCanAccessFullConnectionInfo_UseOpenWifiPackageFromScorerIsNull()
- throws Exception {
- final boolean output;
- mThrowSecurityException = false;
- mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
- mUseOpenWifiPackage = TEST_PACKAGE_NAME;
- mNetworkScorerAppData = new NetworkScorerAppData(0 /*packageUid*/,
- null /*recommendationServiceComp*/, null /*recommendationServiceLabel*/,
- null /*useOpenWifiComponent*/, null /*networkAvailableNotificationChannelId*/);
- setupTestCase();
- WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
- mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
- mMockWifiInjector);
-
- output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME,
- mUid, mTargetVersion);
-
- assertEquals(false, output);
- }
-
- /**
- * Test case setting: Package is invalid because USE_OPEN_WIFI_PACKAGE is an empty string.
- * Location mode is ON
- * User is current
- * The current config is for an open network.
- * Validate result is false
- */
- @Test
- public void testCanAccessFullConnectionInfo_UseOpenWifiPackageIsEmpty() throws Exception {
- final boolean output;
- mThrowSecurityException = false;
- mLocationModeSetting = Settings.Secure.LOCATION_MODE_HIGH_ACCURACY;
- mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
- mUseOpenWifiPackage = "";
- setupTestCase();
- WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
- mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
- mMockWifiInjector);
-
- output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME,
- mUid, mTargetVersion);
-
- assertEquals(false, output);
- }
-
- /**
- * Test case setting: Package is invalid because it does not match the USE_OPEN_WIFI_PACKAGE.
- * User is current
- * The current config is for an open network.
- * Validate result is false
- */
- @Test
- public void testCanAccessFullConnectionInfo_DoesNotMatchUseOpenWifiPackage() throws Exception {
- final boolean output;
- mThrowSecurityException = false;
- mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
- mUseOpenWifiPackage = TEST_PACKAGE_NAME + ".nomatch";
- setupTestCase();
- WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
- mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
- mMockWifiInjector);
-
- output = codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME,
- mUid, mTargetVersion);
-
- assertEquals(false, output);
- }
-
- /**
- * Test case setting: The caller is invalid because its UID does not match the provided package.
- *
- * Validate a SecurityException is thrown.
- */
- @Test
- public void testCanAccessFullConnectionInfo_UidPackageCheckFails() throws Exception {
- mThrowSecurityException = true;
- setupTestCase();
- WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
- mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
- mMockWifiInjector);
-
- try {
- codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME, mUid,
- mTargetVersion);
- fail("SecurityException not thrown.");
- } catch (SecurityException e) {
- // expected
- }
- }
-
- /**
- * Test case setting: The getActiveScorer() call fails with a SecurityException.
- *
- * Validate a SecurityException is thrown.
- */
- @Test
- public void testCanAccessFullConnectionInfo_GetActiveScorerFails() throws Exception {
- mThrowSecurityException = false;
- mGetActiveScorerThrowsSecurityException = true;
- mLocationModeSetting = Settings.Secure.LOCATION_MODE_HIGH_ACCURACY;
- mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
- mUseOpenWifiPackage = TEST_PACKAGE_NAME;
- setupTestCase();
- WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
- mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
- mMockWifiInjector);
-
- try {
- codeUnderTest.canAccessFullConnectionInfo(mMockWifiConfig, TEST_PACKAGE_NAME, mUid,
- mTargetVersion);
- fail("SecurityException not thrown.");
- } catch (SecurityException e) {
- // expected
- }
- }
-
- /**
* Test case Setting: Package is valid
* Legacy App
* Foreground
@@ -700,8 +341,8 @@
mCurrentUser = UserHandle.USER_CURRENT_OR_SELF;
setupTestCase();
WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
- mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
- mMockWifiInjector);
+ mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
+ mWifiInjector);
try {
output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion);
} catch (SecurityException e) {
@@ -732,8 +373,8 @@
mMockUserInfo.id = mCallingUser;
setupTestCase();
WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
- mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
- mMockWifiInjector);
+ mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
+ mWifiInjector);
try {
output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion);
} catch (SecurityException e) {
@@ -759,8 +400,8 @@
mLocationModeSetting = Settings.Secure.LOCATION_MODE_HIGH_ACCURACY;
setupTestCase();
WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
- mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
- mMockWifiInjector);
+ mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
+ mWifiInjector);
try {
output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion);
} catch (SecurityException e) {
@@ -778,8 +419,8 @@
boolean output = false;
setupTestCase();
WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
- mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
- mMockWifiInjector);
+ mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
+ mWifiInjector);
try {
output = codeUnderTest.canAccessScanResults(TEST_PACKAGE_NAME, mUid, mTargetVersion);
} catch (SecurityException e) {
@@ -803,8 +444,8 @@
mMockUserInfo.id = mCallingUser;
setupTestCase();
WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
- mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
- mMockWifiInjector);
+ mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
+ mWifiInjector);
codeUnderTest.enforceLocationPermission(TEST_PACKAGE_NAME, mUid);
}
@@ -816,8 +457,8 @@
public void testEnforceLocationPermissionExpectSecurityException() throws Exception {
setupTestCase();
WifiPermissionsUtil codeUnderTest = new WifiPermissionsUtil(mMockPermissionsWrapper,
- mMockContext, mMockWifiSettingsStore, mMockUserManager, mMockNetworkScoreManager,
- mMockWifiInjector);
+ mMockContext, mMockWifiSettingsStore, mMockUserManager, mNetworkScoreManager,
+ mWifiInjector);
codeUnderTest.enforceLocationPermission(TEST_PACKAGE_NAME, mUid);
}
@@ -859,15 +500,7 @@
when(mMockContext.getContentResolver()).thenReturn(mMockContentResolver);
when(mMockContext.getSystemService(Context.USER_SERVICE))
.thenReturn(mMockUserManager);
- when(mMockWifiInjector.makeLog(anyString())).thenReturn(mWifiLog);
- when(mMockWifiInjector.getFrameworkFacade()).thenReturn(mMockFrameworkFacade);
- if (mGetActiveScorerThrowsSecurityException) {
- when(mMockNetworkScoreManager.getActiveScorer()).thenThrow(
- new SecurityException("Caller is neither the system process nor a "
- + "score requester."));
- } else {
- when(mMockNetworkScoreManager.getActiveScorer()).thenReturn(mNetworkScorerAppData);
- }
+ when(mWifiInjector.makeLog(anyString())).thenReturn(mWifiLog);
}
private void initTestVars() {
@@ -885,10 +518,6 @@
mCoarseLocationPermission = PackageManager.PERMISSION_DENIED;
mAllowCoarseLocationApps = AppOpsManager.MODE_ERRORED;
mActiveNwScorer = false;
- mUseOpenWifiPackage = null;
- mNetworkScorerAppData = null;
- mGetActiveScorerThrowsSecurityException = false;
- mConfigIsOpen = true;
}
private void setupMockInterface() {
@@ -899,14 +528,11 @@
anyString(), anyInt());
when(mMockPermissionsWrapper.getCallingUserId(mUid)).thenReturn(mCallingUser);
when(mMockPermissionsWrapper.getCurrentUser()).thenReturn(mCurrentUser);
- when(mMockNetworkScoreManager.isCallerActiveScorer(mUid)).thenReturn(mActiveNwScorer);
+ when(mNetworkScoreManager.isCallerActiveScorer(mUid)).thenReturn(mActiveNwScorer);
when(mMockPermissionsWrapper.getUidPermission(mManifestStringCoarse, mUid))
.thenReturn(mCoarseLocationPermission);
when(mMockWifiSettingsStore.getLocationModeSetting(mMockContext))
.thenReturn(mLocationModeSetting);
when(mMockPermissionsWrapper.getTopPkgName()).thenReturn(mPkgNameOfTopActivity);
- when(mMockFrameworkFacade.getStringSetting(mMockContext,
- Settings.Global.USE_OPEN_WIFI_PACKAGE)).thenReturn(mUseOpenWifiPackage);
- when(mMockWifiConfig.isOpenNetwork()).thenReturn(mConfigIsOpen);
}
}