Use new common Mutable<E> class. am: faa7b78948 am: 751319a5f4
am: 9841d3a10b
Change-Id: I2dfe02781cf6d37fcd1539461635e9b60c033bd2
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..0fa9652 100644
--- a/service/Android.mk
+++ b/service/Android.mk
@@ -64,8 +64,12 @@
LOCAL_STATIC_JAVA_LIBRARIES := \
android.hardware.wifi-V1.0-java \
android.hardware.wifi-V1.1-java \
- android.hardware.wifi.supplicant-V1.0-java
-LOCAL_REQUIRED_MODULES := services
+ android.hardware.wifi-V1.2-java \
+ android.hardware.wifi.supplicant-V1.0-java \
+ android.hardware.wifi.supplicant-V1.1-java
+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/ExtendedWifiInfo.java b/service/java/com/android/server/wifi/ExtendedWifiInfo.java
new file mode 100644
index 0000000..5edbd34
--- /dev/null
+++ b/service/java/com/android/server/wifi/ExtendedWifiInfo.java
@@ -0,0 +1,123 @@
+/*
+ * 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.net.wifi.WifiInfo;
+
+/**
+ * Extends WifiInfo with the methods for computing the averaged packet rates
+ */
+public class ExtendedWifiInfo extends WifiInfo {
+ private static final long RESET_TIME_STAMP = Long.MIN_VALUE;
+ private static final double FILTER_TIME_CONSTANT = 3000.0;
+
+ private long mLastPacketCountUpdateTimeStamp = RESET_TIME_STAMP;
+
+ @Override
+ public void reset() {
+ super.reset();
+ mLastPacketCountUpdateTimeStamp = RESET_TIME_STAMP;
+ }
+
+ /**
+ * Updates the packet rates using link layer stats
+ *
+ * @param stats WifiLinkLayerStats
+ * @param timeStamp time in milliseconds
+ */
+ public void updatePacketRates(WifiLinkLayerStats stats, long timeStamp) {
+ if (stats != null) {
+ long txgood = stats.txmpdu_be + stats.txmpdu_bk + stats.txmpdu_vi + stats.txmpdu_vo;
+ long txretries = stats.retries_be + stats.retries_bk
+ + stats.retries_vi + stats.retries_vo;
+ long rxgood = stats.rxmpdu_be + stats.rxmpdu_bk + stats.rxmpdu_vi + stats.rxmpdu_vo;
+ long txbad = stats.lostmpdu_be + stats.lostmpdu_bk
+ + stats.lostmpdu_vi + stats.lostmpdu_vo;
+
+ if (mLastPacketCountUpdateTimeStamp != RESET_TIME_STAMP
+ && mLastPacketCountUpdateTimeStamp < timeStamp
+ && txBad <= txbad
+ && txSuccess <= txgood
+ && rxSuccess <= rxgood
+ && txRetries <= txretries) {
+ long timeDelta = timeStamp - mLastPacketCountUpdateTimeStamp;
+ double lastSampleWeight = Math.exp(-1.0 * timeDelta / FILTER_TIME_CONSTANT);
+ double currentSampleWeight = 1.0 - lastSampleWeight;
+
+ txBadRate = txBadRate * lastSampleWeight
+ + (txbad - txBad) * 1000.0 / timeDelta
+ * currentSampleWeight;
+ txSuccessRate = txSuccessRate * lastSampleWeight
+ + (txgood - txSuccess) * 1000.0 / timeDelta
+ * currentSampleWeight;
+ rxSuccessRate = rxSuccessRate * lastSampleWeight
+ + (rxgood - rxSuccess) * 1000.0 / timeDelta
+ * currentSampleWeight;
+ txRetriesRate = txRetriesRate * lastSampleWeight
+ + (txretries - txRetries) * 1000.0 / timeDelta
+ * currentSampleWeight;
+ } else {
+ txBadRate = 0;
+ txSuccessRate = 0;
+ rxSuccessRate = 0;
+ txRetriesRate = 0;
+ }
+ txBad = txbad;
+ txSuccess = txgood;
+ rxSuccess = rxgood;
+ txRetries = txretries;
+ mLastPacketCountUpdateTimeStamp = timeStamp;
+ } else {
+ txBad = 0;
+ txSuccess = 0;
+ rxSuccess = 0;
+ txRetries = 0;
+ txBadRate = 0;
+ txSuccessRate = 0;
+ rxSuccessRate = 0;
+ txRetriesRate = 0;
+ mLastPacketCountUpdateTimeStamp = RESET_TIME_STAMP;
+ }
+ }
+
+ /**
+ * This function is less powerful and used if the WifiLinkLayerStats API is not implemented
+ * at the Wifi HAL
+ *
+ * @hide
+ */
+ public void updatePacketRates(long txPackets, long rxPackets) {
+ //paranoia
+ txBad = 0;
+ txRetries = 0;
+ txBadRate = 0;
+ txRetriesRate = 0;
+ if (txSuccess <= txPackets && rxSuccess <= rxPackets) {
+ txSuccessRate = (txSuccessRate * 0.5)
+ + ((double) (txPackets - txSuccess) * 0.5);
+ rxSuccessRate = (rxSuccessRate * 0.5)
+ + ((double) (rxPackets - rxSuccess) * 0.5);
+ } else {
+ txBadRate = 0;
+ txRetriesRate = 0;
+ }
+ txSuccess = txPackets;
+ rxSuccess = rxPackets;
+ }
+
+
+}
diff --git a/service/java/com/android/server/wifi/FrameworkFacade.java b/service/java/com/android/server/wifi/FrameworkFacade.java
index 2c16444..15b9cc7 100644
--- a/service/java/com/android/server/wifi/FrameworkFacade.java
+++ b/service/java/com/android/server/wifi/FrameworkFacade.java
@@ -65,6 +65,13 @@
}
/**
+ * Mockable facade to Settings.Secure.getInt(.).
+ */
+ public int getSecureIntegerSetting(Context context, String name, int def) {
+ return Settings.Secure.getInt(context.getContentResolver(), name, def);
+ }
+
+ /**
* Helper method for classes to register a ContentObserver
* {@see ContentResolver#registerContentObserver(Uri,boolean,ContentObserver)}.
*
@@ -79,6 +86,17 @@
contentObserver);
}
+ /**
+ * Helper method for classes to unregister a ContentObserver
+ * {@see ContentResolver#unregisterContentObserver(ContentObserver)}.
+ *
+ * @param context
+ * @param contentObserver
+ */
+ public void unregisterContentObserver(Context context, ContentObserver contentObserver) {
+ context.getContentResolver().unregisterContentObserver(contentObserver);
+ }
+
public IBinder getService(String serviceName) {
return ServiceManager.getService(serviceName);
}
diff --git a/service/java/com/android/server/wifi/HalDeviceManager.java b/service/java/com/android/server/wifi/HalDeviceManager.java
index 8623659..8928472 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;
@@ -35,12 +37,12 @@
import android.os.Handler;
import android.os.HidlSupport.Mutable;
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.Pair;
import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
@@ -60,8 +62,9 @@
* Handles device management through the HAL (HIDL) interface.
*/
public class HalDeviceManager {
- private static final String TAG = "HalDeviceManager";
- private static final boolean DBG = false;
+ private static final String TAG = "HalDevMgr";
+ private static final boolean VDBG = false;
+ private boolean mDbg = false;
private static final int START_HAL_RETRY_INTERVAL_MS = 20;
// Number of attempts a start() is re-tried. A value of 0 means no retries after a single
@@ -71,12 +74,27 @@
@VisibleForTesting
public static final String HAL_INSTANCE_NAME = "default";
+ private final Clock mClock;
+
// public API
- public HalDeviceManager() {
- mInterfaceAvailableForRequestListeners.put(IfaceType.STA, new HashSet<>());
- mInterfaceAvailableForRequestListeners.put(IfaceType.AP, new HashSet<>());
- mInterfaceAvailableForRequestListeners.put(IfaceType.P2P, new HashSet<>());
- mInterfaceAvailableForRequestListeners.put(IfaceType.NAN, new HashSet<>());
+ public HalDeviceManager(Clock clock) {
+ mClock = clock;
+
+ mInterfaceAvailableForRequestListeners.put(IfaceType.STA, new HashMap<>());
+ mInterfaceAvailableForRequestListeners.put(IfaceType.AP, new HashMap<>());
+ mInterfaceAvailableForRequestListeners.put(IfaceType.P2P, new HashMap<>());
+ mInterfaceAvailableForRequestListeners.put(IfaceType.NAN, new HashMap<>());
+ }
+
+ /* package */ void enableVerboseLogging(int verbose) {
+ if (verbose > 0) {
+ mDbg = true;
+ } else {
+ mDbg = false;
+ }
+ if (VDBG) {
+ mDbg = true; // just override
+ }
}
/**
@@ -99,12 +117,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");
}
}
@@ -193,37 +213,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);
}
/**
@@ -246,10 +267,11 @@
*/
public IWifiChip getChip(IWifiIface iface) {
String name = getName(iface);
- if (DBG) Log.d(TAG, "getChip: iface(name)=" + name);
+ int type = getType(iface);
+ if (VDBG) Log.d(TAG, "getChip: iface(name)=" + name);
synchronized (mLock) {
- InterfaceCacheEntry cacheEntry = mInterfaceInfoCache.get(name);
+ InterfaceCacheEntry cacheEntry = mInterfaceInfoCache.get(Pair.create(name, type));
if (cacheEntry == null) {
Log.e(TAG, "getChip: no entry for iface(name)=" + name);
return null;
@@ -264,24 +286,29 @@
* 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);
+ int type = getType(iface);
+ if (VDBG) Log.d(TAG, "registerDestroyedListener: iface(name)=" + name);
synchronized (mLock) {
- InterfaceCacheEntry cacheEntry = mInterfaceInfoCache.get(name);
+ InterfaceCacheEntry cacheEntry = mInterfaceInfoCache.get(Pair.create(name, type));
if (cacheEntry == null) {
Log.e(TAG, "registerDestroyedListener: no entry for iface(name)=" + name);
return false;
}
return cacheEntry.destroyedListeners.add(
- new InterfaceDestroyedListenerProxy(destroyedListener,
- looper == null ? Looper.myLooper() : looper));
+ new InterfaceDestroyedListenerProxy(name, destroyedListener, handler));
}
}
@@ -300,17 +327,29 @@
* @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) {
- if (DBG) Log.d(TAG, "registerInterfaceAvailableForRequestListener: ifaceType=" + ifaceType);
+ @NonNull InterfaceAvailableForRequestListener listener, @Nullable Handler handler) {
+ if (VDBG) {
+ Log.d(TAG, "registerInterfaceAvailableForRequestListener: ifaceType=" + ifaceType
+ + ", listener=" + listener + ", handler=" + handler);
+ }
synchronized (mLock) {
- mInterfaceAvailableForRequestListeners.get(ifaceType).add(
- new InterfaceAvailableForRequestListenerProxy(listener,
- looper == null ? Looper.myLooper() : looper));
+ InterfaceAvailableForRequestListenerProxy proxy =
+ new InterfaceAvailableForRequestListenerProxy(listener, handler);
+ if (mInterfaceAvailableForRequestListeners.get(ifaceType).containsKey(proxy)) {
+ if (VDBG) {
+ Log.d(TAG,
+ "registerInterfaceAvailableForRequestListener: dup listener skipped: "
+ + listener);
+ }
+ return;
+ }
+ mInterfaceAvailableForRequestListeners.get(ifaceType).put(proxy, null);
}
WifiChipInfo[] chipInfos = getAllChipInfo();
@@ -329,19 +368,13 @@
public void unregisterInterfaceAvailableForRequestListener(
int ifaceType,
InterfaceAvailableForRequestListener listener) {
- if (DBG) {
+ if (VDBG) {
Log.d(TAG, "unregisterInterfaceAvailableForRequestListener: ifaceType=" + ifaceType);
}
synchronized (mLock) {
- Iterator<InterfaceAvailableForRequestListenerProxy> it =
- mInterfaceAvailableForRequestListeners.get(ifaceType).iterator();
- while (it.hasNext()) {
- if (it.next().mListener == listener) {
- it.remove();
- return;
- }
- }
+ mInterfaceAvailableForRequestListeners.get(ifaceType).remove(
+ new InterfaceAvailableForRequestListenerProxy(listener, null));
}
}
@@ -380,60 +413,67 @@
*
* 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);
}
/**
- * Called when an interface type is possibly available for creation.
+ * Called when an interface type availability for creation is changed.
*/
public interface InterfaceAvailableForRequestListener {
/**
- * Registered when an interface type could be requested. Registered with
+ * Called when an interface type availability for creation is updated. Registered with
* registerInterfaceAvailableForRequestListener() and unregistered with
* unregisterInterfaceAvailableForRequestListener().
*/
- void onAvailableForRequest();
+ void onAvailabilityChanged(boolean isAvailable);
}
/**
- * 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 (VDBG) 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;
}
}
@@ -453,7 +493,7 @@
private IWifi mWifi;
private final WifiEventCallback mWifiEventCallback = new WifiEventCallback();
private final Set<ManagerStatusListenerProxy> mManagerStatusListeners = new HashSet<>();
- private final SparseArray<Set<InterfaceAvailableForRequestListenerProxy>>
+ private final SparseArray<Map<InterfaceAvailableForRequestListenerProxy, Boolean>>
mInterfaceAvailableForRequestListeners = new SparseArray<>();
private final SparseArray<IWifiChipEventCallback.Stub> mDebugCallbacks = new SparseArray<>();
@@ -462,7 +502,8 @@
* we need to keep a list of registered destroyed listeners. Will be validated regularly
* in getAllChipInfoAndValidateCache().
*/
- private final Map<String, InterfaceCacheEntry> mInterfaceInfoCache = new HashMap<>();
+ private final Map<Pair<String, Integer>, InterfaceCacheEntry> mInterfaceInfoCache =
+ new HashMap<>();
private class InterfaceCacheEntry {
public IWifiChip chip;
@@ -470,12 +511,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();
}
@@ -575,7 +618,7 @@
* will be to WTF and continue.
*/
private void initIServiceManagerIfNecessary() {
- if (DBG) Log.d(TAG, "initIServiceManagerIfNecessary");
+ if (mDbg) Log.d(TAG, "initIServiceManagerIfNecessary");
synchronized (mLock) {
if (mServiceManager != null) {
@@ -613,7 +656,7 @@
* @return true if supported, false otherwise.
*/
private boolean isSupportedInternal() {
- if (DBG) Log.d(TAG, "isSupportedInternal");
+ if (VDBG) Log.d(TAG, "isSupportedInternal");
synchronized (mLock) {
if (mServiceManager == null) {
@@ -650,7 +693,7 @@
* Here and elsewhere we assume that death listener will do the right thing!
*/
private void initIWifiIfNecessary() {
- if (DBG) Log.d(TAG, "initIWifiIfNecessary");
+ if (mDbg) Log.d(TAG, "initIWifiIfNecessary");
synchronized (mLock) {
if (mWifi != null) {
@@ -692,9 +735,9 @@
* Relies (to the degree we care) on the service removing all listeners when Wi-Fi is stopped.
*/
private void initIWifiChipDebugListeners() {
- if (DBG) Log.d(TAG, "initIWifiChipDebugListeners");
+ if (VDBG) Log.d(TAG, "initIWifiChipDebugListeners");
- if (!DBG) {
+ if (!VDBG) {
return;
}
@@ -716,7 +759,7 @@
return;
}
- if (DBG) Log.d(TAG, "getChipIds=" + chipIdsResp.value);
+ Log.d(TAG, "getChipIds=" + chipIdsResp.value);
if (chipIdsResp.value.size() == 0) {
Log.e(TAG, "Should have at least 1 chip!");
return;
@@ -799,7 +842,7 @@
* reduce the likelihood that we get out-of-sync).
*/
private WifiChipInfo[] getAllChipInfo() {
- if (DBG) Log.d(TAG, "getAllChipInfo");
+ if (VDBG) Log.d(TAG, "getAllChipInfo");
synchronized (mLock) {
if (mWifi == null) {
@@ -824,7 +867,7 @@
return null;
}
- if (DBG) Log.d(TAG, "getChipIds=" + chipIdsResp.value);
+ if (VDBG) Log.d(TAG, "getChipIds=" + chipIdsResp.value);
if (chipIdsResp.value.size() == 0) {
Log.e(TAG, "Should have at least 1 chip!");
return null;
@@ -1044,7 +1087,7 @@
* found on the information read from the chip.
*/
private boolean validateInterfaceCache(WifiChipInfo[] chipInfos) {
- if (DBG) Log.d(TAG, "validateInterfaceCache");
+ if (VDBG) Log.d(TAG, "validateInterfaceCache");
synchronized (mLock) {
for (InterfaceCacheEntry entry: mInterfaceInfoCache.values()) {
@@ -1086,7 +1129,7 @@
}
private boolean isWifiStarted() {
- if (DBG) Log.d(TAG, "isWifiStart");
+ if (VDBG) Log.d(TAG, "isWifiStart");
synchronized (mLock) {
try {
@@ -1104,7 +1147,7 @@
}
private boolean startWifi() {
- if (DBG) Log.d(TAG, "startWifi");
+ if (VDBG) Log.d(TAG, "startWifi");
synchronized (mLock) {
try {
@@ -1150,7 +1193,7 @@
}
private void stopWifi() {
- if (DBG) Log.d(TAG, "stopWifi");
+ if (VDBG) Log.d(TAG, "stopWifi");
synchronized (mLock) {
try {
@@ -1174,13 +1217,13 @@
private class WifiEventCallback extends IWifiEventCallback.Stub {
@Override
public void onStart() throws RemoteException {
- if (DBG) Log.d(TAG, "IWifiEventCallback.onStart");
+ if (VDBG) Log.d(TAG, "IWifiEventCallback.onStart");
// NOP: only happens in reaction to my calls - will handle directly
}
@Override
public void onStop() throws RemoteException {
- if (DBG) Log.d(TAG, "IWifiEventCallback.onStop");
+ if (VDBG) Log.d(TAG, "IWifiEventCallback.onStop");
// NOP: only happens in reaction to my calls - will handle directly
}
@@ -1203,9 +1246,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
@@ -1266,8 +1308,8 @@
}
private IWifiIface createIface(int ifaceType, InterfaceDestroyedListener destroyedListener,
- Looper looper) {
- if (DBG) Log.d(TAG, "createIface: ifaceType=" + ifaceType);
+ Handler handler) {
+ if (mDbg) Log.d(TAG, "createIface: ifaceType=" + ifaceType);
synchronized (mLock) {
WifiChipInfo[] chipInfos = getAllChipInfo();
@@ -1284,7 +1326,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
@@ -1296,8 +1338,8 @@
}
private IWifiIface createIfaceIfPossible(WifiChipInfo[] chipInfos, int ifaceType,
- InterfaceDestroyedListener destroyedListener, Looper looper) {
- if (DBG) {
+ InterfaceDestroyedListener destroyedListener, Handler handler) {
+ if (VDBG) {
Log.d(TAG, "createIfaceIfPossible: chipInfos=" + Arrays.deepToString(chipInfos)
+ ", ifaceType=" + ifaceType);
}
@@ -1308,7 +1350,7 @@
for (IWifiChip.ChipIfaceCombination chipIfaceCombo : chipMode
.availableCombinations) {
int[][] expandedIfaceCombos = expandIfaceCombos(chipIfaceCombo);
- if (DBG) {
+ if (VDBG) {
Log.d(TAG, chipIfaceCombo + " expands to "
+ Arrays.deepToString(expandedIfaceCombos));
}
@@ -1318,7 +1360,7 @@
chipInfo, chipMode, expandedIfaceCombo, ifaceType);
if (compareIfaceCreationData(currentProposal,
bestIfaceCreationProposal)) {
- if (DBG) Log.d(TAG, "new proposal accepted");
+ if (VDBG) Log.d(TAG, "new proposal accepted");
bestIfaceCreationProposal = currentProposal;
}
}
@@ -1337,12 +1379,14 @@
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);
+ if (mDbg) Log.d(TAG, "createIfaceIfPossible: added cacheEntry=" + cacheEntry);
+ mInterfaceInfoCache.put(
+ Pair.create(cacheEntry.name, cacheEntry.type), cacheEntry);
return iface;
}
}
@@ -1354,7 +1398,7 @@
// similar to createIfaceIfPossible - but simpler code: not looking for best option just
// for any option (so terminates on first one).
private boolean isItPossibleToCreateIface(WifiChipInfo[] chipInfos, int ifaceType) {
- if (DBG) {
+ if (VDBG) {
Log.d(TAG, "isItPossibleToCreateIface: chipInfos=" + Arrays.deepToString(chipInfos)
+ ", ifaceType=" + ifaceType);
}
@@ -1364,7 +1408,7 @@
for (IWifiChip.ChipIfaceCombination chipIfaceCombo : chipMode
.availableCombinations) {
int[][] expandedIfaceCombos = expandIfaceCombos(chipIfaceCombo);
- if (DBG) {
+ if (VDBG) {
Log.d(TAG, chipIfaceCombo + " expands to "
+ Arrays.deepToString(expandedIfaceCombos));
}
@@ -1445,14 +1489,14 @@
*/
private IfaceCreationData canIfaceComboSupportRequest(WifiChipInfo chipInfo,
IWifiChip.ChipMode chipMode, int[] chipIfaceCombo, int ifaceType) {
- if (DBG) {
+ if (VDBG) {
Log.d(TAG, "canIfaceComboSupportRequest: chipInfo=" + chipInfo + ", chipMode="
+ chipMode + ", chipIfaceCombo=" + chipIfaceCombo + ", ifaceType=" + ifaceType);
}
// short-circuit: does the chipIfaceCombo even support the requested type?
if (chipIfaceCombo[ifaceType] == 0) {
- if (DBG) Log.d(TAG, "Requested type not supported by combo");
+ if (VDBG) Log.d(TAG, "Requested type not supported by combo");
return null;
}
@@ -1464,8 +1508,9 @@
if (isChipModeChangeProposed) {
for (int type: IFACE_TYPES_BY_PRIORITY) {
if (chipInfo.ifaces[type].length != 0) {
- if (!allowedToDeleteIfaceTypeForRequestedType(type, ifaceType)) {
- if (DBG) {
+ if (!allowedToDeleteIfaceTypeForRequestedType(type, ifaceType,
+ chipInfo.ifaces)) {
+ if (VDBG) {
Log.d(TAG, "Couldn't delete existing type " + type
+ " interfaces for requested type");
}
@@ -1494,17 +1539,16 @@
}
if (tooManyInterfaces > 0) { // may need to delete some
- if (!allowedToDeleteIfaceTypeForRequestedType(type, ifaceType)) {
- if (DBG) {
+ if (!allowedToDeleteIfaceTypeForRequestedType(type, ifaceType, chipInfo.ifaces)) {
+ if (VDBG) {
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]);
}
}
@@ -1526,7 +1570,7 @@
* - Proposal is better if it means removing fewer high priority interfaces
*/
private boolean compareIfaceCreationData(IfaceCreationData val1, IfaceCreationData val2) {
- if (DBG) Log.d(TAG, "compareIfaceCreationData: val1=" + val1 + ", val2=" + val2);
+ if (VDBG) Log.d(TAG, "compareIfaceCreationData: val1=" + val1 + ", val2=" + val2);
// deal with trivial case of one or the other being null
if (val1 == null) {
@@ -1554,7 +1598,7 @@
}
if (numIfacesToDelete1 < numIfacesToDelete2) {
- if (DBG) {
+ if (VDBG) {
Log.d(TAG, "decision based on type=" + type + ": " + numIfacesToDelete1
+ " < " + numIfacesToDelete2);
}
@@ -1563,7 +1607,7 @@
}
// arbitrary - flip a coin
- if (DBG) Log.d(TAG, "proposals identical - flip a coin");
+ if (VDBG) Log.d(TAG, "proposals identical - flip a coin");
return false;
}
@@ -1571,35 +1615,93 @@
* Returns true if we're allowed to delete the existing interface type for the requested
* interface type.
*
- * Rules:
- * 1. Request for AP or STA will destroy any other interface (except see #4)
- * 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
+ * Rules - applies in order:
+ *
+ * General rules:
+ * 1. No interface will be destroyed for a requested interface of the same type
+ * 2. No interface will be destroyed if one of the requested interfaces already exists
+ * 3. If there are >1 interface of an existing type, then it is ok to destroy that type
+ * interface
+ *
+ * Type-specific rules (but note that the general rules are appied first):
+ * 4. Request for AP or STA will destroy any other interface
+ * 5. Request for P2P will destroy NAN-only (but will destroy a second STA per #3)
+ * 6. Request for NAN will not destroy any interface (but will destroy a second STA per #3)
+
*/
private boolean allowedToDeleteIfaceTypeForRequestedType(int existingIfaceType,
- int requestedIfaceType) {
- // rule 4
+ int requestedIfaceType, WifiIfaceInfo[][] currentIfaces) {
+ // rule 1
if (existingIfaceType == requestedIfaceType) {
return false;
}
+ // rule 2
+ if (currentIfaces[requestedIfaceType].length != 0) {
+ return false;
+ }
+
// rule 3
+ if (currentIfaces[existingIfaceType].length > 1) {
+ return true;
+ }
+
+ // rule 6
if (requestedIfaceType == IfaceType.NAN) {
return false;
}
- // rule 2
+ // rule 5
if (requestedIfaceType == IfaceType.P2P) {
return existingIfaceType == IfaceType.NAN;
}
- // rule 1, the requestIfaceType is either AP or STA
+ // rule 4, the requestIfaceType is either AP or STA
return true;
}
/**
+ * 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 (VDBG) {
+ 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(
+ Pair.create(info.name, getType(info.iface)));
+ 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)
@@ -1609,7 +1711,7 @@
*/
private IWifiIface executeChipReconfiguration(IfaceCreationData ifaceCreationData,
int ifaceType) {
- if (DBG) {
+ if (mDbg) {
Log.d(TAG, "executeChipReconfiguration: ifaceCreationData=" + ifaceCreationData
+ ", ifaceType=" + ifaceType);
}
@@ -1618,7 +1720,7 @@
// is this a mode change?
boolean isModeConfigNeeded = !ifaceCreationData.chipInfo.currentModeIdValid
|| ifaceCreationData.chipInfo.currentModeId != ifaceCreationData.chipModeId;
- if (DBG) Log.d(TAG, "isModeConfigNeeded=" + isModeConfigNeeded);
+ if (mDbg) Log.d(TAG, "isModeConfigNeeded=" + isModeConfigNeeded);
// first delete interfaces/change modes
if (isModeConfigNeeded) {
@@ -1696,7 +1798,13 @@
private boolean removeIfaceInternal(IWifiIface iface) {
String name = getName(iface);
- if (DBG) Log.d(TAG, "removeIfaceInternal: iface(name)=" + name);
+ int type = getType(iface);
+ if (mDbg) Log.d(TAG, "removeIfaceInternal: iface(name)=" + name + ", type=" + type);
+
+ if (type == -1) {
+ Log.e(TAG, "removeIfaceInternal: can't get type -- iface(name)=" + name);
+ return false;
+ }
synchronized (mLock) {
if (mWifi == null) {
@@ -1715,12 +1823,6 @@
return false;
}
- int type = getType(iface);
- if (type == -1) {
- Log.e(TAG, "removeIfaceInternal: can't get type -- iface(name)=" + name);
- return false;
- }
-
WifiStatus status = null;
try {
switch (type) {
@@ -1745,7 +1847,7 @@
}
// dispatch listeners no matter what status
- dispatchDestroyedListeners(name);
+ dispatchDestroyedListeners(name, type);
if (status != null && status.code == WifiStatusCode.SUCCESS) {
return true;
@@ -1759,7 +1861,7 @@
// dispatch all available for request listeners of the specified type AND clean-out the list:
// listeners are called once at most!
private boolean dispatchAvailableForRequestListeners() {
- if (DBG) Log.d(TAG, "dispatchAvailableForRequestListeners");
+ if (VDBG) Log.d(TAG, "dispatchAvailableForRequestListeners");
synchronized (mLock) {
WifiChipInfo[] chipInfos = getAllChipInfo();
@@ -1768,7 +1870,7 @@
stopWifi(); // major error: shutting down
return false;
}
- if (DBG) {
+ if (VDBG) {
Log.d(TAG, "dispatchAvailableForRequestListeners: chipInfos="
+ Arrays.deepToString(chipInfos));
}
@@ -1783,33 +1885,42 @@
private void dispatchAvailableForRequestListenersForType(int ifaceType,
WifiChipInfo[] chipInfos) {
- if (DBG) Log.d(TAG, "dispatchAvailableForRequestListenersForType: ifaceType=" + ifaceType);
+ if (VDBG) Log.d(TAG, "dispatchAvailableForRequestListenersForType: ifaceType=" + ifaceType);
- Set<InterfaceAvailableForRequestListenerProxy> listeners =
- mInterfaceAvailableForRequestListeners.get(ifaceType);
+ synchronized (mLock) {
+ Map<InterfaceAvailableForRequestListenerProxy, Boolean> listeners =
+ mInterfaceAvailableForRequestListeners.get(ifaceType);
- if (listeners.size() == 0) {
- return;
- }
+ if (listeners.size() == 0) {
+ return;
+ }
- if (!isItPossibleToCreateIface(chipInfos, ifaceType)) {
- if (DBG) Log.d(TAG, "Creating interface type isn't possible: ifaceType=" + ifaceType);
- return;
- }
+ boolean isAvailable = isItPossibleToCreateIface(chipInfos, ifaceType);
- if (DBG) Log.d(TAG, "It is possible to create the interface type: ifaceType=" + ifaceType);
- for (InterfaceAvailableForRequestListenerProxy listener : listeners) {
- listener.trigger();
+ if (VDBG) {
+ Log.d(TAG, "Interface available for: ifaceType=" + ifaceType + " = " + isAvailable);
+ }
+ for (Map.Entry<InterfaceAvailableForRequestListenerProxy, Boolean> listenerEntry :
+ listeners.entrySet()) {
+ if (listenerEntry.getValue() == null || listenerEntry.getValue() != isAvailable) {
+ if (VDBG) {
+ Log.d(TAG, "Interface available listener dispatched: ifaceType=" + ifaceType
+ + ", listener=" + listenerEntry.getKey());
+ }
+ listenerEntry.getKey().triggerWithArg(isAvailable);
+ }
+ listenerEntry.setValue(isAvailable);
+ }
}
}
// dispatch all destroyed listeners registered for the specified interface AND remove the
// cache entry
- private void dispatchDestroyedListeners(String name) {
- if (DBG) Log.d(TAG, "dispatchDestroyedListeners: iface(name)=" + name);
+ private void dispatchDestroyedListeners(String name, int type) {
+ if (VDBG) Log.d(TAG, "dispatchDestroyedListeners: iface(name)=" + name);
synchronized (mLock) {
- InterfaceCacheEntry entry = mInterfaceInfoCache.get(name);
+ InterfaceCacheEntry entry = mInterfaceInfoCache.get(Pair.create(name, type));
if (entry == null) {
Log.e(TAG, "dispatchDestroyedListeners: no cache entry for iface(name)=" + name);
return;
@@ -1819,16 +1930,16 @@
listener.trigger();
}
entry.destroyedListeners.clear(); // for insurance (though cache entry is removed)
- mInterfaceInfoCache.remove(name);
+ mInterfaceInfoCache.remove(Pair.create(name, type));
}
}
// dispatch all destroyed listeners registered to all interfaces
private void dispatchAllDestroyedListeners() {
- if (DBG) Log.d(TAG, "dispatchAllDestroyedListeners");
+ if (VDBG) Log.d(TAG, "dispatchAllDestroyedListeners");
synchronized (mLock) {
- Iterator<Map.Entry<String, InterfaceCacheEntry>> it =
+ Iterator<Map.Entry<Pair<String, Integer>, InterfaceCacheEntry>> it =
mInterfaceInfoCache.entrySet().iterator();
while (it.hasNext()) {
InterfaceCacheEntry entry = it.next().getValue();
@@ -1842,8 +1953,6 @@
}
private abstract class ListenerProxy<LISTENER> {
- private static final int LISTENER_TRIGGERED = 0;
-
protected LISTENER mListener;
private Handler mHandler;
@@ -1860,55 +1969,60 @@
}
void trigger() {
- mHandler.sendMessage(mHandler.obtainMessage(LISTENER_TRIGGERED));
+ if (mHandler != null) {
+ mHandler.post(() -> {
+ action();
+ });
+ } else {
+ action();
+ }
}
- protected abstract void action();
+ void triggerWithArg(boolean arg) {
+ if (mHandler != null) {
+ mHandler.post(() -> {
+ actionWithArg(arg);
+ });
+ } else {
+ actionWithArg(arg);
+ }
+ }
- ListenerProxy(LISTENER listener, Looper looper, String tag) {
+ protected void action() {}
+ protected void actionWithArg(boolean arg) {}
+
+ 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
- protected void action() {
- mListener.onAvailableForRequest();
+ protected void actionWithArg(boolean isAvailable) {
+ mListener.onAvailabilityChanged(isAvailable);
}
}
diff --git a/service/java/com/android/server/wifi/LegacyConnectedScore.java b/service/java/com/android/server/wifi/LegacyConnectedScore.java
index facab0a..3027696 100644
--- a/service/java/com/android/server/wifi/LegacyConnectedScore.java
+++ b/service/java/com/android/server/wifi/LegacyConnectedScore.java
@@ -63,6 +63,10 @@
private boolean mMultiBandScanResults;
private boolean mIsHomeNetwork;
private int mScore = 0;
+ private int mBadRssiCount;
+ private int mLinkStuckCount;
+ private int mLowRssiCount;
+
LegacyConnectedScore(Context context, WifiConfigManager wifiConfigManager, Clock clock) {
super(clock);
@@ -109,32 +113,32 @@
rssi += WifiConfiguration.HOME_NETWORK_RSSI_BOOST;
}
- if ((wifiInfo.txBadRate >= 1)
- && (wifiInfo.txSuccessRate < MAX_SUCCESS_RATE_OF_STUCK_LINK)
+ if ((wifiInfo.txBadRate * 5 >= 1)
+ && (wifiInfo.txSuccessRate * 5 < MAX_SUCCESS_RATE_OF_STUCK_LINK)
&& rssi < rssiThreshLow) {
// Link is stuck
- if (wifiInfo.linkStuckCount < MAX_STUCK_LINK_COUNT) {
- wifiInfo.linkStuckCount += 1;
+ if (mLinkStuckCount < MAX_STUCK_LINK_COUNT) {
+ mLinkStuckCount += 1;
}
- } else if (wifiInfo.txBadRate < MIN_TX_FAILURE_RATE_FOR_WORKING_LINK) {
- if (wifiInfo.linkStuckCount > 0) {
- wifiInfo.linkStuckCount -= 1;
+ } else if (wifiInfo.txBadRate * 5 < MIN_TX_FAILURE_RATE_FOR_WORKING_LINK) {
+ if (mLinkStuckCount > 0) {
+ mLinkStuckCount -= 1;
}
}
if (rssi < rssiThreshBad) {
- if (wifiInfo.badRssiCount < MAX_BAD_RSSI_COUNT) {
- wifiInfo.badRssiCount += 1;
+ if (mBadRssiCount < MAX_BAD_RSSI_COUNT) {
+ mBadRssiCount += 1;
}
} else if (rssi < rssiThreshLow) {
- wifiInfo.lowRssiCount = MAX_LOW_RSSI_COUNT; // Dont increment the lowRssi count above 1
- if (wifiInfo.badRssiCount > 0) {
+ mLowRssiCount = MAX_LOW_RSSI_COUNT; // Dont increment the lowRssi count above 1
+ if (mBadRssiCount > 0) {
// Decrement bad Rssi count
- wifiInfo.badRssiCount -= 1;
+ mBadRssiCount -= 1;
}
} else {
- wifiInfo.badRssiCount = 0;
- wifiInfo.lowRssiCount = 0;
+ mBadRssiCount = 0;
+ mLowRssiCount = 0;
}
// Ugh, we need to finish the score calculation while we have wifiInfo
@@ -155,6 +159,9 @@
@Override
public void reset() {
mScore = 0;
+ mBadRssiCount = 0;
+ mLinkStuckCount = 0;
+ mLowRssiCount = 0;
}
/**
@@ -182,18 +189,19 @@
int linkSpeed = wifiInfo.getLinkSpeed();
- if (wifiInfo.linkStuckCount > MIN_SUSTAINED_LINK_STUCK_COUNT) {
+ if (mLinkStuckCount > MIN_SUSTAINED_LINK_STUCK_COUNT) {
// Once link gets stuck for more than 3 seconds, start reducing the score
- score = score - LINK_STUCK_PENALTY * (wifiInfo.linkStuckCount - 1);
+ score = score - LINK_STUCK_PENALTY * (mLinkStuckCount - 1);
}
if (linkSpeed < linkspeedThreshBad) {
score -= BAD_LINKSPEED_PENALTY;
- } else if ((linkSpeed >= linkspeedThreshGood) && (wifiInfo.txSuccessRate > 5)) {
+ } else if ((linkSpeed >= linkspeedThreshGood)
+ && (wifiInfo.txSuccessRate > 1)) {
score += GOOD_LINKSPEED_BONUS; // So as bad rssi alone doesn't kill us
}
- score -= wifiInfo.badRssiCount * BAD_RSSI_COUNT_PENALTY + wifiInfo.lowRssiCount;
+ score -= mBadRssiCount * BAD_RSSI_COUNT_PENALTY + mLowRssiCount;
if (rssi >= rssiThreshSaturated) score += 5;
diff --git a/service/java/com/android/server/wifi/SavedNetworkEvaluator.java b/service/java/com/android/server/wifi/SavedNetworkEvaluator.java
index 59d4ab2..97f6b6f 100644
--- a/service/java/com/android/server/wifi/SavedNetworkEvaluator.java
+++ b/service/java/com/android/server/wifi/SavedNetworkEvaluator.java
@@ -25,8 +25,6 @@
import com.android.internal.R;
import com.android.server.wifi.util.TelephonyUtil;
-import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
/**
@@ -242,96 +240,83 @@
for (ScanDetail scanDetail : scanDetails) {
ScanResult scanResult = scanDetail.getScanResult();
- int highestScoreOfScanResult = Integer.MIN_VALUE;
- int candidateIdOfScanResult = WifiConfiguration.INVALID_NETWORK_ID;
// One ScanResult can be associated with more than one networks, hence we calculate all
// the scores and use the highest one as the ScanResult's score.
- List<WifiConfiguration> associatedConfigurations = null;
- WifiConfiguration associatedConfiguration =
+ WifiConfiguration network =
mWifiConfigManager.getConfiguredNetworkForScanDetailAndCache(scanDetail);
- if (associatedConfiguration == null) {
+ if (network == null) {
continue;
- } else {
- associatedConfigurations =
- new ArrayList<>(Arrays.asList(associatedConfiguration));
}
- for (WifiConfiguration network : associatedConfigurations) {
- /**
- * Ignore Passpoint and Ephemeral networks. They are configured networks,
- * but without being persisted to the storage. They are evaluated by
- * {@link PasspointNetworkEvaluator} and {@link ScoredNetworkEvaluator}
- * respectively.
- */
- if (network.isPasspoint() || network.isEphemeral()) {
- continue;
- }
+ /**
+ * Ignore Passpoint and Ephemeral networks. They are configured networks,
+ * but without being persisted to the storage. They are evaluated by
+ * {@link PasspointNetworkEvaluator} and {@link ScoredNetworkEvaluator}
+ * respectively.
+ */
+ if (network.isPasspoint() || network.isEphemeral()) {
+ continue;
+ }
- WifiConfiguration.NetworkSelectionStatus status =
- network.getNetworkSelectionStatus();
- status.setSeenInLastQualifiedNetworkSelection(true);
+ WifiConfiguration.NetworkSelectionStatus status =
+ network.getNetworkSelectionStatus();
+ status.setSeenInLastQualifiedNetworkSelection(true);
- if (!status.isNetworkEnabled()) {
- continue;
- } else if (network.BSSID != null && !network.BSSID.equals("any")
- && !network.BSSID.equals(scanResult.BSSID)) {
- // App has specified the only BSSID to connect for this
- // configuration. So only the matching ScanResult can be a candidate.
- localLog("Network " + WifiNetworkSelector.toNetworkString(network)
- + " has specified BSSID " + network.BSSID + ". Skip "
- + scanResult.BSSID);
- continue;
- } else if (TelephonyUtil.isSimConfig(network)
- && !mWifiConfigManager.isSimPresent()) {
- // Don't select if security type is EAP SIM/AKA/AKA' when SIM is not present.
- continue;
- }
+ if (!status.isNetworkEnabled()) {
+ continue;
+ } else if (network.BSSID != null && !network.BSSID.equals("any")
+ && !network.BSSID.equals(scanResult.BSSID)) {
+ // App has specified the only BSSID to connect for this
+ // configuration. So only the matching ScanResult can be a candidate.
+ localLog("Network " + WifiNetworkSelector.toNetworkString(network)
+ + " has specified BSSID " + network.BSSID + ". Skip "
+ + scanResult.BSSID);
+ continue;
+ } else if (TelephonyUtil.isSimConfig(network)
+ && !mWifiConfigManager.isSimPresent()) {
+ // Don't select if security type is EAP SIM/AKA/AKA' when SIM is not present.
+ continue;
+ }
- int score = calculateBssidScore(scanResult, network, currentNetwork, currentBssid,
- scoreHistory);
+ int score = calculateBssidScore(scanResult, network, currentNetwork, currentBssid,
+ scoreHistory);
- // Set candidate ScanResult for all saved networks to ensure that users can
- // override network selection. See WifiNetworkSelector#setUserConnectChoice.
- // TODO(b/36067705): consider alternative designs to push filtering/selecting of
- // user connect choice networks to RecommendedNetworkEvaluator.
- if (score > status.getCandidateScore() || (score == status.getCandidateScore()
- && status.getCandidate() != null
- && scanResult.level > status.getCandidate().level)) {
- mWifiConfigManager.setNetworkCandidateScanResult(
- network.networkId, scanResult, score);
- }
+ // Set candidate ScanResult for all saved networks to ensure that users can
+ // override network selection. See WifiNetworkSelector#setUserConnectChoice.
+ // TODO(b/36067705): consider alternative designs to push filtering/selecting of
+ // user connect choice networks to RecommendedNetworkEvaluator.
+ if (score > status.getCandidateScore() || (score == status.getCandidateScore()
+ && status.getCandidate() != null
+ && scanResult.level > status.getCandidate().level)) {
+ mWifiConfigManager.setNetworkCandidateScanResult(
+ network.networkId, scanResult, score);
+ }
- // If the network is marked to use external scores, or is an open network with
- // curate saved open networks enabled, do not consider it for network selection.
- if (network.useExternalScores) {
- localLog("Network " + WifiNetworkSelector.toNetworkString(network)
- + " has external score.");
- continue;
- }
-
- if (score > highestScoreOfScanResult) {
- highestScoreOfScanResult = score;
- candidateIdOfScanResult = network.networkId;
- }
+ // If the network is marked to use external scores, or is an open network with
+ // curate saved open networks enabled, do not consider it for network selection.
+ if (network.useExternalScores) {
+ localLog("Network " + WifiNetworkSelector.toNetworkString(network)
+ + " has external score.");
+ continue;
}
if (connectableNetworks != null) {
connectableNetworks.add(Pair.create(scanDetail,
- mWifiConfigManager.getConfiguredNetwork(candidateIdOfScanResult)));
+ mWifiConfigManager.getConfiguredNetwork(network.networkId)));
}
- if (highestScoreOfScanResult > highestScore
- || (highestScoreOfScanResult == highestScore
+ if (score > highestScore
+ || (score == highestScore
&& scanResultCandidate != null
&& scanResult.level > scanResultCandidate.level)) {
- highestScore = highestScoreOfScanResult;
+ highestScore = score;
scanResultCandidate = scanResult;
mWifiConfigManager.setNetworkCandidateScanResult(
- candidateIdOfScanResult, scanResultCandidate, highestScore);
+ network.networkId, scanResultCandidate, highestScore);
// Reload the network config with the updated info.
- candidate = mWifiConfigManager.getConfiguredNetwork(candidateIdOfScanResult);
+ candidate = mWifiConfigManager.getConfiguredNetwork(network.networkId);
}
}
diff --git a/service/java/com/android/server/wifi/SoftApManager.java b/service/java/com/android/server/wifi/SoftApManager.java
index d4a1ea5..6d5fd27 100644
--- a/service/java/com/android/server/wifi/SoftApManager.java
+++ b/service/java/com/android/server/wifi/SoftApManager.java
@@ -20,23 +20,35 @@
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.database.ContentObserver;
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.Handler;
import android.os.INetworkManagementService;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.text.TextUtils;
import android.util.Log;
+import android.util.Pair;
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
+import com.android.internal.util.WakeupMessage;
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 +58,15 @@
public class SoftApManager implements ActiveModeManager {
private static final String TAG = "SoftApManager";
+ // Minimum limit to use for timeout delay if the value from overlay setting is too small.
+ private static final int MIN_SOFT_AP_TIMEOUT_DELAY_MS = 600_000; // 10 minutes
+
+ @VisibleForTesting
+ public static final String SOFT_AP_SEND_MESSAGE_TIMEOUT_TAG = TAG
+ + " Soft AP Send Message Timeout";
+
+ private final Context mContext;
+ private final FrameworkFacade mFrameworkFacade;
private final WifiNative mWifiNative;
private final String mCountryCode;
@@ -54,16 +75,29 @@
private final Listener mListener;
- private final IApInterface mApInterface;
+ private IApInterface mApInterface;
+ private String mApInterfaceName;
private final INetworkManagementService mNwService;
private final WifiApConfigStore mWifiApConfigStore;
private final WifiMetrics mWifiMetrics;
+ private final int mMode;
private WifiConfiguration mApConfig;
/**
+ * Listener for soft AP events.
+ */
+ 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.
*/
public interface Listener {
@@ -75,29 +109,32 @@
void onStateChanged(int state, int failureReason);
}
- public SoftApManager(Looper looper,
+ public SoftApManager(Context context,
+ Looper looper,
+ FrameworkFacade framework,
WifiNative wifiNative,
String countryCode,
Listener listener,
- IApInterface apInterface,
INetworkManagementService nms,
WifiApConfigStore wifiApConfigStore,
- WifiConfiguration config,
+ @NonNull SoftApModeConfiguration apConfig,
WifiMetrics wifiMetrics) {
- mStateMachine = new SoftApStateMachine(looper);
-
+ mContext = context;
+ mFrameworkFacade = framework;
mWifiNative = wifiNative;
mCountryCode = countryCode;
mListener = listener;
- mApInterface = apInterface;
mNwService = nms;
mWifiApConfigStore = wifiApConfigStore;
+ mMode = apConfig.getTargetMode();
+ WifiConfiguration config = apConfig.getWifiConfiguration();
if (config == null) {
mApConfig = mWifiApConfigStore.getApConfiguration();
} else {
mApConfig = config;
}
mWifiMetrics = wifiMetrics;
+ mStateMachine = new SoftApStateMachine(looper);
}
/**
@@ -116,12 +153,38 @@
/**
* 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);
+ }
+
+ /**
+ * Helper function to increment the appropriate setup failure metrics.
+ */
+ private void incrementMetricsForSetupFailure(int failureReason) {
+ if (failureReason == WifiNative.SETUP_FAILURE_HAL) {
+ mWifiMetrics.incrementNumWifiOnFailureDueToHal();
+ } else if (failureReason == WifiNative.SETUP_FAILURE_WIFICOND) {
+ mWifiMetrics.incrementNumWifiOnFailureDueToWificond();
}
}
@@ -142,6 +205,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,72 +222,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.
+ * Teardown soft AP and teardown the interface.
*/
private void stopSoftAp() {
- try {
- mApInterface.stopHostapd();
- } catch (RemoteException e) {
- Log.e(TAG, "Exception in stopping soft AP: " + e);
- return;
+ if (!mWifiNative.stopSoftAp()) {
+ Log.e(TAG, "Soft AP stop failed");
}
Log.d(TAG, "Soft AP is stopped");
}
@@ -232,14 +248,18 @@
// 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;
+ public static final int CMD_NO_ASSOCIATED_STATIONS_TIMEOUT = 5;
+ public static final int CMD_TIMEOUT_TOGGLE_CHANGED = 6;
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,68 @@
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();
+ // need to create our interface
+ mApInterface = null;
+ Pair<Integer, IApInterface> statusAndInterface =
+ mWifiNative.setupForSoftApMode(mWifiNative.getInterfaceName());
+ if (statusAndInterface.first == WifiNative.SETUP_SUCCESS) {
+ mApInterface = statusAndInterface.second;
+ } else {
+ Log.e(TAG, "setup failure when creating ap interface.");
+ incrementMetricsForSetupFailure(statusAndInterface.first);
+ }
+ if (mApInterface == null) {
+ Log.e(TAG, "Not starting softap mode without an interface.");
updateApState(WifiManager.WIFI_AP_STATE_FAILED,
- WifiManager.SAP_START_FAILURE_GENERAL);
+ WifiManager.WIFI_AP_STATE_DISABLED,
+ WifiManager.SAP_START_FAILURE_GENERAL);
+ mWifiMetrics.incrementSoftApStartResult(
+ false, WifiManager.SAP_START_FAILURE_GENERAL);
+ break;
+ }
+ try {
+ mApInterfaceName = mApInterface.getInterfaceName();
+ } catch (RemoteException e) {
+ // Failed to get the interface name. This is not a good sign and we
+ // should report a failure.
+ Log.e(TAG, "Failed to get the 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;
}
+ // 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);
+ 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 +374,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;
}
@@ -340,6 +407,92 @@
private class StartedState extends State {
private boolean mIfaceIsUp;
+ private int mNumAssociatedStations;
+
+ private boolean mTimeoutEnabled;
+ private int mTimeoutDelay;
+ private WakeupMessage mSoftApTimeoutMessage;
+ private SoftApTimeoutEnabledSettingObserver mSettingObserver;
+
+ /**
+ * Observer for timeout settings changes.
+ */
+ private class SoftApTimeoutEnabledSettingObserver extends ContentObserver {
+ SoftApTimeoutEnabledSettingObserver(Handler handler) {
+ super(handler);
+ }
+
+ public void register() {
+ mFrameworkFacade.registerContentObserver(mContext,
+ Settings.Global.getUriFor(Settings.Global.SOFT_AP_TIMEOUT_ENABLED),
+ true, this);
+ mTimeoutEnabled = getValue();
+ }
+
+ public void unregister() {
+ mFrameworkFacade.unregisterContentObserver(mContext, this);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ super.onChange(selfChange);
+ mStateMachine.sendMessage(SoftApStateMachine.CMD_TIMEOUT_TOGGLE_CHANGED,
+ getValue() ? 1 : 0);
+ }
+
+ private boolean getValue() {
+ boolean enabled = mFrameworkFacade.getIntegerSetting(mContext,
+ Settings.Global.SOFT_AP_TIMEOUT_ENABLED, 1) == 1;
+ return enabled;
+ }
+ }
+
+ private int getConfigSoftApTimeoutDelay() {
+ int delay = mContext.getResources().getInteger(
+ R.integer.config_wifi_framework_soft_ap_timeout_delay);
+ if (delay < MIN_SOFT_AP_TIMEOUT_DELAY_MS) {
+ delay = MIN_SOFT_AP_TIMEOUT_DELAY_MS;
+ Log.w(TAG, "Overriding timeout delay with minimum limit value");
+ }
+ Log.d(TAG, "Timeout delay: " + delay);
+ return delay;
+ }
+
+ private void scheduleTimeoutMessage() {
+ if (!mTimeoutEnabled) {
+ return;
+ }
+ mSoftApTimeoutMessage.schedule(SystemClock.elapsedRealtime() + mTimeoutDelay);
+ Log.d(TAG, "Timeout message scheduled");
+ }
+
+ private void cancelTimeoutMessage() {
+ mSoftApTimeoutMessage.cancel();
+ Log.d(TAG, "Timeout message canceled");
+ }
+
+ /**
+ * 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);
+
+ if (mNumAssociatedStations == 0) {
+ scheduleTimeoutMessage();
+ } else {
+ cancelTimeoutMessage();
+ }
+ }
+
private void onUpChanged(boolean isUp) {
if (isUp == mIfaceIsUp) {
return; // no change
@@ -347,11 +500,13 @@
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);
}
@Override
@@ -359,17 +514,62 @@
mIfaceIsUp = false;
InterfaceConfiguration config = null;
try {
- config = mNwService.getInterfaceConfig(mApInterface.getInterfaceName());
+ config = mNwService.getInterfaceConfig(mApInterfaceName);
} catch (RemoteException e) {
}
if (config != null) {
onUpChanged(config.isUp());
}
+
+ mTimeoutDelay = getConfigSoftApTimeoutDelay();
+ Handler handler = mStateMachine.getHandler();
+ mSoftApTimeoutMessage = new WakeupMessage(mContext, handler,
+ SOFT_AP_SEND_MESSAGE_TIMEOUT_TAG,
+ SoftApStateMachine.CMD_NO_ASSOCIATED_STATIONS_TIMEOUT);
+ mSettingObserver = new SoftApTimeoutEnabledSettingObserver(handler);
+
+ if (mSettingObserver != null) {
+ mSettingObserver.register();
+ }
+ Log.d(TAG, "Resetting num stations on start");
+ mNumAssociatedStations = 0;
+ scheduleTimeoutMessage();
+ }
+
+ @Override
+ public void exit() {
+ if (mSettingObserver != null) {
+ mSettingObserver.unregister();
+ }
+ Log.d(TAG, "Resetting num stations on stop");
+ mNumAssociatedStations = 0;
+ cancelTimeoutMessage();
}
@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;
+ }
+ Log.d(TAG, "Setting num stations on CMD_NUM_ASSOCIATED_STATIONS_CHANGED");
+ setNumAssociatedStations(message.arg1);
+ break;
+ case CMD_TIMEOUT_TOGGLE_CHANGED:
+ boolean isEnabled = (message.arg1 == 1);
+ if (mTimeoutEnabled == isEnabled) {
+ break;
+ }
+ mTimeoutEnabled = isEnabled;
+ if (!mTimeoutEnabled) {
+ cancelTimeoutMessage();
+ }
+ if (mTimeoutEnabled && mNumAssociatedStations == 0) {
+ scheduleTimeoutMessage();
+ }
+ break;
case CMD_INTERFACE_STATUS_CHANGED:
if (message.obj != mNetworkObserver) {
// This is from some time before the most recent configuration.
@@ -381,17 +581,35 @@
case CMD_START:
// Already started, ignore this command.
break;
- case CMD_AP_INTERFACE_BINDER_DEATH:
+ case CMD_NO_ASSOCIATED_STATIONS_TIMEOUT:
+ if (!mTimeoutEnabled) {
+ Log.wtf(TAG, "Timeout message received while timeout is disabled."
+ + " Dropping.");
+ break;
+ }
+ if (mNumAssociatedStations != 0) {
+ Log.wtf(TAG, "Timeout message received but has clients. Dropping.");
+ break;
+ }
+ Log.i(TAG, "Timeout message received. Stopping soft AP.");
+ 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);
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 +617,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 d22046c..3fcf880 100644
--- a/service/java/com/android/server/wifi/SupplicantStaIfaceHal.java
+++ b/service/java/com/android/server/wifi/SupplicantStaIfaceHal.java
@@ -54,6 +54,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;
@@ -70,6 +71,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;
@@ -97,8 +99,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) {
@@ -107,11 +116,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.");
}
}
}
@@ -132,16 +141,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();
}
/**
@@ -184,7 +187,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.
@@ -253,11 +256,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;
@@ -270,22 +273,59 @@
}
}
- 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) {
+ ISupplicantIface ifaceHwBinder;
+ if (isV1_1()) {
+ ifaceHwBinder = addIfaceV1_1(ifaceName);
+ } else {
+ ifaceHwBinder = getIfaceV1_0(ifaceName);
+ }
+ if (ifaceHwBinder == null) {
+ Log.e(TAG, "setupIface got null iface");
+ return false;
+ }
+ ISupplicantStaIface iface = getStaIfaceMockable(ifaceHwBinder);
+ if (!linkToSupplicantStaIfaceDeath(iface)) {
+ return false;
+ }
+ ISupplicantStaIfaceCallback callback = new SupplicantStaIfaceHalCallback(ifaceName);
+ if (!registerCallback(iface, callback)) {
+ return false;
+ }
+ mISupplicantStaIfaces.put(ifaceName, iface);
+ mISupplicantStaIfaceCallbacks.put(ifaceName, callback);
+ return true;
+ }
+
+ /**
+ * Get a STA interface for the specified iface name.
+ *
+ * @param ifaceName Name of the interface.
+ * @return true on success, false otherwise.
+ */
+ private ISupplicantIface getIfaceV1_0(@NonNull String ifaceName) {
synchronized (mLock) {
/** List all supplicant Ifaces */
final ArrayList<ISupplicant.IfaceInfo> supplicantIfaces = new ArrayList<>();
try {
mISupplicant.listInterfaces((SupplicantStatus status,
- ArrayList<ISupplicant.IfaceInfo> ifaces) -> {
+ ArrayList<ISupplicant.IfaceInfo> ifaces) -> {
if (status.code != SupplicantStatusCode.SUCCESS) {
Log.e(TAG, "Getting Supplicant Interfaces failed: " + status.code);
return;
@@ -294,54 +334,169 @@
});
} catch (RemoteException e) {
Log.e(TAG, "ISupplicant.listInterfaces exception: " + e);
- return false;
+ supplicantServiceDiedHandler(ifaceName);
+ return null;
}
if (supplicantIfaces.size() == 0) {
Log.e(TAG, "Got zero HIDL supplicant ifaces. Stopping supplicant HIDL startup.");
- return false;
+ return null;
}
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) -> {
- if (status.code != SupplicantStatusCode.SUCCESS) {
- Log.e(TAG, "Failed to get ISupplicantIface " + status.code);
- return;
- }
- supplicantIface.value = iface;
- });
+ if (status.code != SupplicantStatusCode.SUCCESS) {
+ Log.e(TAG, "Failed to get ISupplicantIface " + status.code);
+ return;
+ }
+ supplicantIface.value = iface;
+ });
} catch (RemoteException e) {
Log.e(TAG, "ISupplicant.getInterface exception: " + e);
- return false;
+ supplicantServiceDiedHandler(ifaceName);
+ return null;
}
- ifaceName.value = ifaceInfo.name;
break;
}
}
- if (supplicantIface.value == null) {
- Log.e(TAG, "initSupplicantStaIface got null iface");
+ return supplicantIface.value;
+ }
+ }
+
+ /**
+ * Create a STA interface for the specified iface name.
+ *
+ * @param ifaceName Name of the interface.
+ * @return true on success, false otherwise.
+ */
+ private ISupplicantIface addIfaceV1_1(@NonNull String ifaceName) {
+ synchronized (mLock) {
+ ISupplicant.IfaceInfo ifaceInfo = new ISupplicant.IfaceInfo();
+ ifaceInfo.name = ifaceName;
+ ifaceInfo.type = IfaceType.STA;
+ Mutable<ISupplicantIface> supplicantIface = new Mutable<>();
+ try {
+ getSupplicantMockableV1_1().addInterface(ifaceInfo,
+ (SupplicantStatus status, ISupplicantIface iface) -> {
+ if (status.code != SupplicantStatusCode.SUCCESS
+ && status.code != SupplicantStatusCode.FAILURE_IFACE_EXISTS) {
+ Log.e(TAG, "Failed to create ISupplicantIface " + status.code);
+ return;
+ }
+ supplicantIface.value = iface;
+ });
+ } catch (RemoteException e) {
+ Log.e(TAG, "ISupplicant.createInterface exception: " + e);
+ supplicantServiceDiedHandler(ifaceName);
+ return null;
+ }
+ return supplicantIface.value;
+ }
+ }
+
+ /**
+ * 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 (isV1_1()) {
+ if (!removeIfaceV1_1(ifaceName)) {
+ Log.e(TAG, "Failed to remove iface = " + ifaceName);
+ return false;
+ }
+ }
+ if (mISupplicantStaIfaces.remove(ifaceName) == null) {
+ Log.e(TAG, "Trying to teardown unknown inteface");
return false;
}
- mISupplicantStaIface = getStaIfaceMockable(supplicantIface.value);
- mIfaceName = ifaceName.value;
- if (!linkToSupplicantStaIfaceDeath()) {
- return false;
- }
- if (!registerCallback(mISupplicantStaIfaceCallback)) {
+ mISupplicantStaIfaceCallbacks.remove(ifaceName);
+ return true;
+ }
+ }
+
+ /**
+ * Remove a STA interface for the specified iface name.
+ *
+ * @param ifaceName Name of the interface.
+ * @return true on success, false otherwise.
+ */
+ private boolean removeIfaceV1_1(@NonNull String ifaceName) {
+ synchronized (mLock) {
+ try {
+ ISupplicant.IfaceInfo ifaceInfo = new ISupplicant.IfaceInfo();
+ ifaceInfo.name = ifaceName;
+ ifaceInfo.type = IfaceType.STA;
+ SupplicantStatus status = getSupplicantMockableV1_1().removeInterface(ifaceInfo);
+ if (status.code != SupplicantStatusCode.SUCCESS) {
+ Log.e(TAG, "Failed to remove iface " + status.code);
+ return false;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "ISupplicant.getInterface exception: " + e);
+ supplicantServiceDiedHandler(ifaceName);
return false;
}
return true;
}
}
- private void supplicantServiceDiedHandler() {
+ /**
+ * 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;
+ }
+
+
+ private void clearState() {
synchronized (mLock) {
mISupplicant = null;
- mISupplicantStaIface = null;
- mWifiMonitor.broadcastSupplicantDisconnectionEvent(mIfaceName);
+ mISupplicantStaIfaces.clear();
+ mCurrentNetworkLocalConfigs.clear();
+ mCurrentNetworkRemoteHandles.clear();
+ }
+ }
+
+ private void supplicantServiceDiedHandler(@NonNull String ifaceName) {
+ synchronized (mLock) {
+ mWifiMonitor.broadcastSupplicantDisconnectionEvent(ifaceName);
+ clearState();
+ }
+ }
+
+ private void supplicantServiceDiedHandler() {
+ synchronized (mLock) {
+ if (mDeathEventHandler != null) {
+ mDeathEventHandler.onDeath();
+ }
+ for (String ifaceName : mISupplicantStaIfaces.keySet()) {
+ mWifiMonitor.broadcastSupplicantDisconnectionEvent(ifaceName);
+ }
+ clearState();
}
}
@@ -359,7 +514,7 @@
*/
public boolean isInitializationComplete() {
synchronized (mLock) {
- return mISupplicantStaIface != null;
+ return mISupplicant != null;
}
}
@@ -378,6 +533,14 @@
}
}
+ protected android.hardware.wifi.supplicant.V1_1.ISupplicant getSupplicantMockableV1_1()
+ throws RemoteException {
+ synchronized (mLock) {
+ return android.hardware.wifi.supplicant.V1_1.ISupplicant.castFrom(
+ ISupplicant.getService());
+ }
+ }
+
protected ISupplicantStaIface getStaIfaceMockable(ISupplicantIface iface) {
synchronized (mLock) {
return ISupplicantStaIface.asInterface(iface.asBinder());
@@ -385,6 +548,43 @@
}
/**
+ * Check if the device is running V1_1 supplicant service.
+ * @return
+ */
+ private boolean isV1_1() {
+ synchronized (mLock) {
+ try {
+ return (getSupplicantMockableV1_1() != null);
+ } catch (RemoteException e) {
+ Log.e(TAG, "ISupplicant.getService exception: " + e);
+ supplicantServiceDiedHandler();
+ return false;
+ }
+ }
+ }
+
+ /**
+ * 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.
@@ -392,14 +592,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;
@@ -412,7 +612,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;
@@ -428,32 +628,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;
}
@@ -470,23 +688,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;
}
@@ -497,21 +719,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;
@@ -540,7 +763,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);
}
}
@@ -552,37 +775,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;
}
}
@@ -590,113 +816,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();
}
}
@@ -705,13 +970,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;
@@ -722,6 +988,7 @@
}
if (newNetwork.value != null) {
return getStaNetworkMockable(
+ ifaceName,
ISupplicantStaNetwork.asInterface(newNetwork.value.asBinder()));
} else {
return null;
@@ -734,12 +1001,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);
@@ -751,15 +1019,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);
@@ -772,14 +1041,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;
}
@@ -789,6 +1058,7 @@
}
if (gotNetwork.value != null) {
return getStaNetworkMockable(
+ ifaceName,
ISupplicantStaNetwork.asInterface(gotNetwork.value.asBinder()));
} else {
return null;
@@ -797,12 +1067,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);
@@ -815,14 +1086,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;
}
@@ -837,15 +1108,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);
@@ -857,10 +1130,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);
@@ -877,7 +1151,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;
@@ -885,12 +1159,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);
@@ -902,15 +1177,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);
@@ -922,15 +1199,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);
@@ -942,15 +1221,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);
@@ -962,15 +1243,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);
@@ -982,26 +1265,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);
@@ -1013,14 +1298,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);
@@ -1032,14 +1319,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);
@@ -1051,14 +1340,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);
@@ -1070,15 +1361,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);
@@ -1090,13 +1383,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;
@@ -1104,12 +1399,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);
@@ -1121,13 +1417,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;
@@ -1135,12 +1432,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);
@@ -1151,13 +1449,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;
@@ -1166,12 +1466,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);
@@ -1183,16 +1484,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);
@@ -1202,14 +1506,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);
@@ -1221,14 +1526,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;
@@ -1237,13 +1544,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);
@@ -1255,15 +1563,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);
@@ -1279,14 +1589,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);
@@ -1298,14 +1610,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);
@@ -1317,11 +1631,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) {
@@ -1335,16 +1650,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);
@@ -1356,11 +1672,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) {
@@ -1374,16 +1691,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);
@@ -1395,12 +1713,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) {
@@ -1417,16 +1736,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);
@@ -1437,16 +1757,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);
@@ -1458,15 +1780,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);
@@ -1478,23 +1802,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);
@@ -1506,15 +1832,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;
@@ -1523,12 +1851,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);
@@ -1540,13 +1869,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;
@@ -1555,12 +1885,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);
@@ -1572,16 +1903,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);
@@ -1593,13 +1926,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;
@@ -1608,13 +1942,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;
@@ -1630,14 +1965,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);
@@ -1649,15 +1986,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);
@@ -1667,12 +2006,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);
@@ -1760,13 +2100,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;
}
}
@@ -1911,9 +2268,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.
*
@@ -1982,10 +2343,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);
}
}
@@ -2056,10 +2418,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..bfc51f6
--- /dev/null
+++ b/service/java/com/android/server/wifi/VelocityBasedConnectedScore.java
@@ -0,0 +1,193 @@
+/*
+ * 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});
+ } else {
+ double dt = (millis - mLastMillis) * 0.001;
+ mFilter.mR.put(0, 0, standardDeviation * standardDeviation);
+ setDeltaTimeSeconds(dt);
+ mFilter.predict();
+ mFilter.update(new Matrix(1, new double[]{rssi}));
+ }
+ mLastMillis = millis;
+ 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;
+ }
+
+ private double mMinimumPpsForMeasuringSuccess = 2.0;
+
+ /**
+ * 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;
+ double txSuccessPps = wifiInfo.txSuccessRate;
+ double rxSuccessPps = wifiInfo.rxSuccessRate;
+ if (txSuccessPps < mMinimumPpsForMeasuringSuccess) return;
+ if (rxSuccessPps < mMinimumPpsForMeasuringSuccess) return;
+ double txBadPps = wifiInfo.txBadRate;
+ double probabilityOfSuccessfulTx = txSuccessPps / (txSuccessPps + txBadPps);
+ 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/WakeupConfigStoreData.java b/service/java/com/android/server/wifi/WakeupConfigStoreData.java
new file mode 100644
index 0000000..5775117
--- /dev/null
+++ b/service/java/com/android/server/wifi/WakeupConfigStoreData.java
@@ -0,0 +1,179 @@
+/*
+ * 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.util.ArraySet;
+
+import com.android.server.wifi.WifiConfigStore.StoreData;
+import com.android.server.wifi.util.XmlUtil;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Set;
+
+/**
+ * Config store data for Wifi Wake.
+ */
+public class WakeupConfigStoreData implements StoreData {
+ private static final String TAG = "WakeupConfigStoreData";
+
+ private static final String XML_TAG_IS_ACTIVE = "IsActive";
+ private static final String XML_TAG_NETWORK_SECTION = "Network";
+ private static final String XML_TAG_SSID = "SSID";
+ private static final String XML_TAG_SECURITY = "Security";
+
+ private final DataSource<Boolean> mIsActiveDataSource;
+ private final DataSource<Set<ScanResultMatchInfo>> mNetworkDataSource;
+
+ /**
+ * Interface defining a data source for the store data.
+ *
+ * @param <T> Type of data source
+ */
+ public interface DataSource<T> {
+ /**
+ * Returns the data from the data source.
+ */
+ T getData();
+
+ /**
+ * Updates the data in the data source.
+ *
+ * @param data Data retrieved from the store
+ */
+ void setData(T data);
+ }
+
+ /**
+ * Creates the config store data with its data sources.
+ *
+ * @param isActiveDataSource Data source for isActive
+ * @param networkDataSource Data source for the locked network list
+ */
+ public WakeupConfigStoreData(
+ DataSource<Boolean> isActiveDataSource,
+ DataSource<Set<ScanResultMatchInfo>> networkDataSource) {
+ mIsActiveDataSource = isActiveDataSource;
+ mNetworkDataSource = networkDataSource;
+ }
+
+ @Override
+ public void serializeData(XmlSerializer out, boolean shared)
+ throws XmlPullParserException, IOException {
+ if (shared) {
+ throw new XmlPullParserException("Share data not supported");
+ }
+
+ XmlUtil.writeNextValue(out, XML_TAG_IS_ACTIVE, mIsActiveDataSource.getData());
+
+ for (ScanResultMatchInfo scanResultMatchInfo : mNetworkDataSource.getData()) {
+ writeNetwork(out, scanResultMatchInfo);
+ }
+ }
+
+ /**
+ * Writes a {@link ScanResultMatchInfo} to an XML output stream.
+ *
+ * @param out XML output stream
+ * @param scanResultMatchInfo The ScanResultMatchInfo to serizialize
+ * @throws XmlPullParserException
+ * @throws IOException
+ */
+ private void writeNetwork(XmlSerializer out, ScanResultMatchInfo scanResultMatchInfo)
+ throws XmlPullParserException, IOException {
+ XmlUtil.writeNextSectionStart(out, XML_TAG_NETWORK_SECTION);
+
+ XmlUtil.writeNextValue(out, XML_TAG_SSID, scanResultMatchInfo.networkSsid);
+ XmlUtil.writeNextValue(out, XML_TAG_SECURITY, scanResultMatchInfo.networkType);
+
+ XmlUtil.writeNextSectionEnd(out, XML_TAG_NETWORK_SECTION);
+ }
+
+ @Override
+ public void deserializeData(XmlPullParser in, int outerTagDepth, boolean shared)
+ throws XmlPullParserException, IOException {
+ if (shared) {
+ throw new XmlPullParserException("Shared data not supported");
+ }
+
+ boolean isActive = (Boolean) XmlUtil.readNextValueWithName(in, XML_TAG_IS_ACTIVE);
+ mIsActiveDataSource.setData(isActive);
+
+ Set<ScanResultMatchInfo> networks = new ArraySet<>();
+ while (XmlUtil.gotoNextSectionWithNameOrEnd(in, XML_TAG_NETWORK_SECTION, outerTagDepth)) {
+ networks.add(parseNetwork(in, outerTagDepth + 1));
+ }
+
+ mNetworkDataSource.setData(networks);
+ }
+
+ /**
+ * Parses a {@link ScanResultMatchInfo} from an XML input stream.
+ *
+ * @param in XML input stream
+ * @param outerTagDepth XML tag depth of the containing section
+ * @return The {@link ScanResultMatchInfo}
+ * @throws IOException
+ * @throws XmlPullParserException
+ */
+ private ScanResultMatchInfo parseNetwork(XmlPullParser in, int outerTagDepth)
+ throws IOException, XmlPullParserException {
+ ScanResultMatchInfo scanResultMatchInfo = new ScanResultMatchInfo();
+ while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
+ String[] valueName = new String[1];
+ Object value = XmlUtil.readCurrentValue(in, valueName);
+ if (valueName[0] == null) {
+ throw new XmlPullParserException("Missing value name");
+ }
+ switch (valueName[0]) {
+ case XML_TAG_SSID:
+ scanResultMatchInfo.networkSsid = (String) value;
+ break;
+ case XML_TAG_SECURITY:
+ scanResultMatchInfo.networkType = (int) value;
+ break;
+ default:
+ throw new XmlPullParserException("Unknown tag under " + TAG + ": "
+ + valueName[0]);
+ }
+ }
+
+ return scanResultMatchInfo;
+ }
+
+ @Override
+ public void resetData(boolean shared) {
+ if (!shared) {
+ mNetworkDataSource.setData(Collections.emptySet());
+ mIsActiveDataSource.setData(false);
+ }
+ }
+
+ @Override
+ public String getName() {
+ return TAG;
+ }
+
+ @Override
+ public boolean supportShareData() {
+ return false;
+ }
+}
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..4e84c4a
--- /dev/null
+++ b/service/java/com/android/server/wifi/WakeupController.java
@@ -0,0 +1,236 @@
+/*
+ * 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.net.wifi.ScanResult;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiScanner;
+import android.os.Handler;
+import android.os.Looper;
+import android.provider.Settings;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+
+/**
+ * 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 {
+
+ private static final String TAG = "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;
+ private final WakeupLock mWakeupLock;
+ private final WifiConfigManager mWifiConfigManager;
+ private final WifiInjector mWifiInjector;
+
+ private final WifiScanner.ScanListener mScanListener = new WifiScanner.ScanListener() {
+ @Override
+ public void onPeriodChanged(int periodInMs) {
+ // no-op
+ }
+
+ @Override
+ public void onResults(WifiScanner.ScanData[] results) {
+ // TODO(easchwar) handle scan results
+ }
+
+ @Override
+ public void onFullResult(ScanResult fullScanResult) {
+ // no-op
+ }
+
+ @Override
+ public void onSuccess() {
+ // no-op
+ }
+
+ @Override
+ public void onFailure(int reason, String description) {
+ Log.e(TAG, "ScanListener onFailure: " + reason + ": " + description);
+ }
+ };
+
+ /** Whether this feature is enabled in Settings. */
+ private boolean mWifiWakeupEnabled;
+
+ /** Whether the WakeupController is currently active. */
+ private boolean mIsActive = false;
+
+ public WakeupController(
+ Context context,
+ Looper looper,
+ WakeupLock wakeupLock,
+ WifiConfigManager wifiConfigManager,
+ WifiConfigStore wifiConfigStore,
+ WifiInjector wifiInjector,
+ FrameworkFacade frameworkFacade) {
+ mContext = context;
+ mHandler = new Handler(looper);
+ mWakeupLock = wakeupLock;
+ mWifiConfigManager = wifiConfigManager;
+ mFrameworkFacade = frameworkFacade;
+ mWifiInjector = wifiInjector;
+ 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 */);
+
+ // registering the store data here has the effect of reading the persisted value of the
+ // data sources after system boot finishes
+ WakeupConfigStoreData wakeupConfigStoreData =
+ new WakeupConfigStoreData(new IsActiveDataSource(), mWakeupLock.getDataSource());
+ wifiConfigStore.registerStoreData(wakeupConfigStoreData);
+ }
+
+ private void setActive(boolean isActive) {
+ if (mIsActive != isActive) {
+ mIsActive = isActive;
+ mWifiConfigManager.saveToStore(false /* forceWrite */);
+ }
+ }
+
+ /**
+ * Starts listening for incoming scans.
+ *
+ * <p>Should only be called upon entering ScanMode. WakeupController registers its listener with
+ * the WifiScanner. If the WakeupController is already active, then it returns early. Otherwise
+ * it performs its initialization steps and sets {@link #mIsActive} to true.
+ */
+ public void start() {
+ mWifiInjector.getWifiScanner().registerScanListener(mScanListener);
+
+ // If already active, we don't want to re-initialize the lock, so return early.
+ if (mIsActive) {
+ return;
+ }
+ setActive(true);
+
+ if (mWifiWakeupEnabled) {
+ mWakeupLock.initialize(getMostRecentSavedScanResults());
+ }
+ }
+
+ /**
+ * Stops listening for scans.
+ *
+ * <p>Should only be called upon leaving ScanMode. It deregisters the listener from
+ * WifiScanner.
+ */
+ public void stop() {
+ mWifiInjector.getWifiScanner().deregisterScanListener(mScanListener);
+ }
+
+ /** Resets the WakeupController, setting {@link #mIsActive} to false. */
+ public void reset() {
+ setActive(false);
+ }
+
+ /** Returns a list of saved networks from the last full scan. */
+ private Set<ScanResultMatchInfo> getMostRecentSavedScanResults() {
+ Set<ScanResultMatchInfo> goodSavedNetworks = getGoodSavedNetworks();
+
+ List<ScanResult> scanResults = mWifiInjector.getWifiScanner().getSingleScanResults();
+ Set<ScanResultMatchInfo> lastSeenNetworks = new HashSet<>(scanResults.size());
+ for (ScanResult scanResult : scanResults) {
+ lastSeenNetworks.add(ScanResultMatchInfo.fromScanResult(scanResult));
+ }
+
+ lastSeenNetworks.retainAll(goodSavedNetworks);
+ return lastSeenNetworks;
+ }
+
+ /** Returns a filtered list of saved networks from WifiConfigManager. */
+ private Set<ScanResultMatchInfo> getGoodSavedNetworks() {
+ List<WifiConfiguration> savedNetworks = mWifiConfigManager.getSavedNetworks();
+
+ Set<ScanResultMatchInfo> goodSavedNetworks = new HashSet<>(savedNetworks.size());
+ for (WifiConfiguration config : savedNetworks) {
+ if (isWideAreaNetwork(config)
+ || config.hasNoInternetAccess()
+ || config.noInternetAccessExpected
+ || !config.getNetworkSelectionStatus().getHasEverConnected()) {
+ continue;
+ }
+ goodSavedNetworks.add(ScanResultMatchInfo.fromWifiConfiguration(config));
+ }
+
+ Log.d(TAG, "getGoodSavedNetworks: " + goodSavedNetworks.size());
+ return goodSavedNetworks;
+ }
+
+ //TODO(b/69271702) implement WAN filtering
+ private boolean isWideAreaNetwork(WifiConfiguration wifiConfiguration) {
+ return false;
+ }
+
+ /**
+ * 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;
+ }
+
+ /** Dumps wakeup controller state. */
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("Dump of WakeupController");
+ pw.println("mWifiWakeupEnabled: " + mWifiWakeupEnabled);
+ pw.println("USE_PLATFORM_WIFI_WAKE: " + USE_PLATFORM_WIFI_WAKE);
+ pw.println("mIsActive: " + mIsActive);
+ mWakeupLock.dump(fd, pw, args);
+ }
+
+ private class IsActiveDataSource implements WakeupConfigStoreData.DataSource<Boolean> {
+
+ @Override
+ public Boolean getData() {
+ return mIsActive;
+ }
+
+ @Override
+ public void setData(Boolean data) {
+ mIsActive = data;
+ }
+ }
+}
diff --git a/service/java/com/android/server/wifi/WakeupEvaluator.java b/service/java/com/android/server/wifi/WakeupEvaluator.java
new file mode 100644
index 0000000..df9c43d
--- /dev/null
+++ b/service/java/com/android/server/wifi/WakeupEvaluator.java
@@ -0,0 +1,89 @@
+/*
+ * 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.net.wifi.ScanResult;
+
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.Collection;
+
+/**
+ * Evaluates ScanResults for Wifi Wake.
+ */
+public class WakeupEvaluator {
+
+ private final int mThresholdMinimumRssi24;
+ private final int mThresholdMinimumRssi5;
+
+ /**
+ * Constructs a {@link WakeupEvaluator} using the given context.
+ */
+ public static WakeupEvaluator fromContext(Context context) {
+ int minimumRssi24 = context.getResources().getInteger(
+ R.integer.config_wifi_framework_wifi_score_entry_rssi_threshold_24GHz);
+ int minimumRssi5 = context.getResources().getInteger(
+ R.integer.config_wifi_framework_wifi_score_entry_rssi_threshold_5GHz);
+ return new WakeupEvaluator(minimumRssi24, minimumRssi5);
+ }
+
+ @VisibleForTesting
+ WakeupEvaluator(int minimumRssi24, int minimumRssi5) {
+ mThresholdMinimumRssi24 = minimumRssi24;
+ mThresholdMinimumRssi5 = minimumRssi5;
+ }
+
+ /**
+ * Searches ScanResults to find a connectable network.
+ *
+ * <p>This method searches the given ScanResults for one that is present in the given
+ * ScanResultMatchInfos and has a sufficiently high RSSI. If there is no such ScanResult, it
+ * returns null. If there are multiple, it returns the one with the highest RSSI.
+ *
+ * @param scanResults ScanResults to search
+ * @param savedNetworks Network list to compare against
+ * @return The {@link ScanResult} representing an in-range connectable network, or {@code null}
+ * signifying there is no viable network
+ */
+ public ScanResult findViableNetwork(Collection<ScanResult> scanResults,
+ Collection<ScanResultMatchInfo> savedNetworks) {
+ ScanResult selectedScanResult = null;
+
+ for (ScanResult scanResult : scanResults) {
+ if (isBelowThreshold(scanResult)) {
+ continue;
+ }
+ if (savedNetworks.contains(ScanResultMatchInfo.fromScanResult(scanResult))) {
+ if (selectedScanResult == null || selectedScanResult.level < scanResult.level) {
+ selectedScanResult = scanResult;
+ }
+ }
+ }
+
+ return selectedScanResult;
+ }
+
+ /**
+ * Returns whether the given ScanResult's signal strength is below the selection threshold.
+ */
+ public boolean isBelowThreshold(ScanResult scanResult) {
+ return ((scanResult.is24GHz() && scanResult.level < mThresholdMinimumRssi24)
+ || (scanResult.is5GHz() && scanResult.level < mThresholdMinimumRssi5));
+ }
+}
diff --git a/service/java/com/android/server/wifi/WakeupLock.java b/service/java/com/android/server/wifi/WakeupLock.java
new file mode 100644
index 0000000..1fcd9f8
--- /dev/null
+++ b/service/java/com/android/server/wifi/WakeupLock.java
@@ -0,0 +1,142 @@
+/*
+ * 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.util.ArrayMap;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A lock to determine whether Auto Wifi can re-enable Wifi.
+ *
+ * <p>Wakeuplock manages a list of networks to determine whether the device's location has changed.
+ */
+public class WakeupLock {
+
+ private static final String TAG = WakeupLock.class.getSimpleName();
+
+ @VisibleForTesting
+ static final int CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT = 3;
+
+
+ private final WifiConfigManager mWifiConfigManager;
+ private final Map<ScanResultMatchInfo, Integer> mLockedNetworks = new ArrayMap<>();
+
+ public WakeupLock(WifiConfigManager wifiConfigManager) {
+ mWifiConfigManager = wifiConfigManager;
+ }
+
+ /**
+ * Initializes the WakeupLock with the given {@link ScanResultMatchInfo} list.
+ *
+ * <p>This saves the wakeup lock to the store.
+ *
+ * @param scanResultList list of ScanResultMatchInfos to start the lock with
+ */
+ public void initialize(Collection<ScanResultMatchInfo> scanResultList) {
+ mLockedNetworks.clear();
+ for (ScanResultMatchInfo scanResultMatchInfo : scanResultList) {
+ mLockedNetworks.put(scanResultMatchInfo, CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT);
+ }
+
+ Log.d(TAG, "Lock initialized. Number of networks: " + mLockedNetworks.size());
+
+ mWifiConfigManager.saveToStore(false /* forceWrite */);
+ }
+
+ /**
+ * Updates the lock with the given {@link ScanResultMatchInfo} list.
+ *
+ * <p>If a network in the lock is not present in the list, reduce the number of scans
+ * required to evict by one. Remove any entries in the list with 0 scans required to evict. If
+ * any entries in the lock are removed, the store is updated.
+ *
+ * @param scanResultList list of present ScanResultMatchInfos to update the lock with
+ */
+ public void update(Collection<ScanResultMatchInfo> scanResultList) {
+ boolean hasChanged = false;
+ Iterator<Map.Entry<ScanResultMatchInfo, Integer>> it =
+ mLockedNetworks.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry<ScanResultMatchInfo, Integer> entry = it.next();
+
+ // if present in scan list, reset to max
+ if (scanResultList.contains(entry.getKey())) {
+ entry.setValue(CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT);
+ continue;
+ }
+
+ // decrement and remove if necessary
+ entry.setValue(entry.getValue() - 1);
+ if (entry.getValue() <= 0) {
+ it.remove();
+ hasChanged = true;
+ }
+ }
+
+ if (hasChanged) {
+ mWifiConfigManager.saveToStore(false /* forceWrite */);
+ }
+ }
+
+ /**
+ * Returns whether the internal network set is empty.
+ */
+ public boolean isEmpty() {
+ return mLockedNetworks.isEmpty();
+ }
+
+ /** Returns the data source for the WakeupLock config store data. */
+ public WakeupConfigStoreData.DataSource<Set<ScanResultMatchInfo>> getDataSource() {
+ return new WakeupLockDataSource();
+ }
+
+ /** Dumps wakeup lock contents. */
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("WakeupLock: ");
+ pw.println("Locked networks: " + mLockedNetworks.size());
+ for (Map.Entry<ScanResultMatchInfo, Integer> entry : mLockedNetworks.entrySet()) {
+ pw.println(entry.getKey() + ", scans to evict: " + entry.getValue());
+ }
+ }
+
+ private class WakeupLockDataSource
+ implements WakeupConfigStoreData.DataSource<Set<ScanResultMatchInfo>> {
+
+ @Override
+ public Set<ScanResultMatchInfo> getData() {
+ return mLockedNetworks.keySet();
+ }
+
+ @Override
+ public void setData(Set<ScanResultMatchInfo> data) {
+ mLockedNetworks.clear();
+ for (ScanResultMatchInfo network : data) {
+ mLockedNetworks.put(network, CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT);
+ }
+
+ }
+ }
+}
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/WifiCertManager.java b/service/java/com/android/server/wifi/WifiCertManager.java
deleted file mode 100644
index e180f51..0000000
--- a/service/java/com/android/server/wifi/WifiCertManager.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2015 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.app.admin.IDevicePolicyManager;
-import android.content.Context;
-import android.os.Environment;
-import android.os.ServiceManager;
-import android.os.UserHandle;
-import android.security.Credentials;
-import android.security.KeyStore;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.android.server.net.DelayedDiskWrite;
-
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Manager class for affiliated Wifi certificates.
- */
-public class WifiCertManager {
- private static final String TAG = "WifiCertManager";
- private static final String SEP = "\n";
-
- private final Context mContext;
- private final Set<String> mAffiliatedUserOnlyCerts = new HashSet<String>();
- private final String mConfigFile;
-
- private static final String CONFIG_FILE =
- Environment.getDataDirectory() + "/misc/wifi/affiliatedcerts.txt";
-
- private final DelayedDiskWrite mWriter = new DelayedDiskWrite();
-
-
- WifiCertManager(Context context) {
- this(context, CONFIG_FILE);
- }
-
- WifiCertManager(Context context, String configFile) {
- mContext = context;
- mConfigFile = configFile;
- final byte[] bytes = readConfigFile();
- if (bytes == null) {
- // Config file does not exist or empty.
- return;
- }
-
- String[] keys = new String(bytes, StandardCharsets.UTF_8).split(SEP);
- for (String key : keys) {
- mAffiliatedUserOnlyCerts.add(key);
- }
-
- // Remove keys that no longer exist in KeyStore.
- if (mAffiliatedUserOnlyCerts.retainAll(Arrays.asList(listClientCertsForAllUsers()))) {
- writeConfig();
- }
- }
-
- /** @param key Unprefixed cert key to hide from unaffiliated users. */
- public void hideCertFromUnaffiliatedUsers(String key) {
- if (mAffiliatedUserOnlyCerts.add(Credentials.USER_PRIVATE_KEY + key)) {
- writeConfig();
- }
- }
-
- /** @return Prefixed cert keys that are visible to the current user. */
- public String[] listClientCertsForCurrentUser() {
- HashSet<String> results = new HashSet<String>();
-
- String[] keys = listClientCertsForAllUsers();
- if (isAffiliatedUser()) {
- return keys;
- }
-
- for (String key : keys) {
- if (!mAffiliatedUserOnlyCerts.contains(key)) {
- results.add(key);
- }
- }
- return results.toArray(new String[results.size()]);
- }
-
- private void writeConfig() {
- String[] values =
- mAffiliatedUserOnlyCerts.toArray(new String[mAffiliatedUserOnlyCerts.size()]);
- String value = TextUtils.join(SEP, values);
- writeConfigFile(value.getBytes(StandardCharsets.UTF_8));
- }
-
- protected byte[] readConfigFile() {
- byte[] bytes = null;
- try {
- final File file = new File(mConfigFile);
- final long fileSize = file.exists() ? file.length() : 0;
- if (fileSize == 0 || fileSize >= Integer.MAX_VALUE) {
- // Config file is empty/corrupted/non-existing.
- return bytes;
- }
-
- bytes = new byte[(int) file.length()];
- final DataInputStream stream = new DataInputStream(new FileInputStream(file));
- stream.readFully(bytes);
- } catch (IOException e) {
- Log.e(TAG, "readConfigFile: failed to read " + e, e);
- }
- return bytes;
- }
-
- protected void writeConfigFile(byte[] payload) {
- final byte[] data = payload;
- mWriter.write(mConfigFile, new DelayedDiskWrite.Writer() {
- public void onWriteCalled(DataOutputStream out) throws IOException {
- out.write(data, 0, data.length);
- }
- });
- }
-
- protected String[] listClientCertsForAllUsers() {
- return KeyStore.getInstance().list(Credentials.USER_PRIVATE_KEY, UserHandle.myUserId());
- }
-
- protected boolean isAffiliatedUser() {
- IDevicePolicyManager pm = IDevicePolicyManager.Stub.asInterface(
- ServiceManager.getService(Context.DEVICE_POLICY_SERVICE));
- boolean result = false;
- try {
- result = pm.isAffiliatedUser();
- } catch (Exception e) {
- Log.e(TAG, "failed to check user affiliation", e);
- }
- return result;
- }
-}
diff --git a/service/java/com/android/server/wifi/WifiConfigManager.java b/service/java/com/android/server/wifi/WifiConfigManager.java
index f256396..8855d6d 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;
}
@@ -2369,8 +2349,7 @@
Iterator<WifiConfiguration> iter = networks.iterator();
while (iter.hasNext()) {
WifiConfiguration config = iter.next();
- if (!config.hiddenSSID ||
- config.getNetworkSelectionStatus().isNetworkPermanentlyDisabled()) {
+ if (!config.hiddenSSID) {
iter.remove();
}
}
@@ -2776,6 +2755,10 @@
* @return Whether the write was successful or not, this is applicable only for force writes.
*/
public boolean saveToStore(boolean forceWrite) {
+ if (mPendingStoreRead) {
+ Log.e(TAG, "Cannot save to store before store is read!");
+ return false;
+ }
ArrayList<WifiConfiguration> sharedConfigurations = new ArrayList<>();
ArrayList<WifiConfiguration> userConfigurations = new ArrayList<>();
// List of network IDs for legacy Passpoint configuration to be removed.
diff --git a/service/java/com/android/server/wifi/WifiConfigurationUtil.java b/service/java/com/android/server/wifi/WifiConfigurationUtil.java
index d1afeb2..fc298e7 100644
--- a/service/java/com/android/server/wifi/WifiConfigurationUtil.java
+++ b/service/java/com/android/server/wifi/WifiConfigurationUtil.java
@@ -441,9 +441,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.
@@ -461,13 +462,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/WifiConnectivityManager.java b/service/java/com/android/server/wifi/WifiConnectivityManager.java
index 458f73a..c67e7c6 100644
--- a/service/java/com/android/server/wifi/WifiConnectivityManager.java
+++ b/service/java/com/android/server/wifi/WifiConnectivityManager.java
@@ -814,24 +814,38 @@
}
}
+ boolean isScanNeeded = true;
boolean isFullBandScan = true;
+ boolean isTrafficOverThreshold = mWifiInfo.txSuccessRate > mFullScanMaxTxRate
+ || mWifiInfo.rxSuccessRate > mFullScanMaxRxRate;
- // If the WiFi traffic is heavy, only partial scan is initiated.
- if (mWifiState == WIFI_STATE_CONNECTED
- && (mWifiInfo.txSuccessRate > mFullScanMaxTxRate
- || mWifiInfo.rxSuccessRate > mFullScanMaxRxRate)) {
- localLog("No full band scan due to ongoing traffic");
- isFullBandScan = false;
+ // If the WiFi traffic is heavy, only partial scan is proposed.
+ if (mWifiState == WIFI_STATE_CONNECTED && isTrafficOverThreshold) {
+ // If only partial scan is proposed and firmware roaming control is supported,
+ // we will not issue any scan because firmware roaming will take care of
+ // intra-SSID roam.
+ if (mConnectivityHelper.isFirmwareRoamingSupported()) {
+ localLog("No partial scan because firmware roaming is supported.");
+ isScanNeeded = false;
+ } else {
+ localLog("No full band scan due to ongoing traffic");
+ isFullBandScan = false;
+ }
}
- mLastPeriodicSingleScanTimeStamp = currentTimeStamp;
- startSingleScan(isFullBandScan, WIFI_WORK_SOURCE);
- schedulePeriodicScanTimer(mPeriodicSingleScanInterval);
+ if (isScanNeeded) {
+ mLastPeriodicSingleScanTimeStamp = currentTimeStamp;
+ startSingleScan(isFullBandScan, WIFI_WORK_SOURCE);
+ schedulePeriodicScanTimer(mPeriodicSingleScanInterval);
- // Set up the next scan interval in an exponential backoff fashion.
- mPeriodicSingleScanInterval *= 2;
- if (mPeriodicSingleScanInterval > MAX_PERIODIC_SCAN_INTERVAL_MS) {
- mPeriodicSingleScanInterval = MAX_PERIODIC_SCAN_INTERVAL_MS;
+ // Set up the next scan interval in an exponential backoff fashion.
+ mPeriodicSingleScanInterval *= 2;
+ if (mPeriodicSingleScanInterval > MAX_PERIODIC_SCAN_INTERVAL_MS) {
+ mPeriodicSingleScanInterval = MAX_PERIODIC_SCAN_INTERVAL_MS;
+ }
+ } else {
+ // Since we already skipped this scan, keep the same scan interval for next scan.
+ schedulePeriodicScanTimer(mPeriodicSingleScanInterval);
}
}
diff --git a/service/java/com/android/server/wifi/WifiController.java b/service/java/com/android/server/wifi/WifiController.java
index 494ce86..dc98595 100644
--- a/service/java/com/android/server/wifi/WifiController.java
+++ b/service/java/com/android/server/wifi/WifiController.java
@@ -93,6 +93,7 @@
/* References to values tracked in WifiService */
private final WifiStateMachine mWifiStateMachine;
+ private final WifiStateMachinePrime mWifiStateMachinePrime;
private final WifiSettingsStore mSettingsStore;
private final WifiLockManager mWifiLockManager;
@@ -143,11 +144,13 @@
private EcmState mEcmState = new EcmState();
WifiController(Context context, WifiStateMachine wsm, WifiSettingsStore wss,
- WifiLockManager wifiLockManager, Looper looper, FrameworkFacade f) {
+ WifiLockManager wifiLockManager, Looper looper, FrameworkFacade f,
+ WifiStateMachinePrime wsmp) {
super(TAG, looper);
mFacade = f;
mContext = context;
mWifiStateMachine = wsm;
+ mWifiStateMachinePrime = wsmp;
mSettingsStore = wss;
mWifiLockManager = wifiLockManager;
@@ -435,7 +438,8 @@
@Override
public void enter() {
mWifiStateMachine.setSupplicantRunning(false);
- // Supplicant can't restart right away, so not the time we switched off
+ mWifiStateMachinePrime.disableWifi();
+ // Supplicant can't restart right away, so note the time we switched off
mDisabledTimestamp = SystemClock.elapsedRealtime();
mDeferredEnableSerialNumber++;
mHaveDeferredEnable = false;
@@ -481,6 +485,7 @@
}
mWifiStateMachine.setHostApRunning((SoftApModeConfiguration) msg.obj,
true);
+ mWifiStateMachinePrime.enterSoftAPMode((SoftApModeConfiguration) msg.obj);
transitionTo(mApEnabledState);
}
break;
@@ -565,8 +570,13 @@
if (msg.arg1 == 1) {
// remeber that we were enabled
mSettingsStore.setWifiSavedState(WifiSettingsStore.WIFI_ENABLED);
- deferMessage(obtainMessage(msg.what, msg.arg1, 1, msg.obj));
- transitionTo(mApStaDisabledState);
+ mWifiStateMachine.setHostApRunning((SoftApModeConfiguration) msg.obj, true);
+ mWifiStateMachinePrime.enterSoftAPMode((SoftApModeConfiguration) msg.obj);
+ transitionTo(mApEnabledState);
+ // we should just go directly to ApEnabled since we will kill interfaces
+ // from WSMP
+ //deferMessage(obtainMessage(msg.what, msg.arg1, 1, msg.obj));
+ //transitionTo(mApStaDisabledState);
}
break;
default:
@@ -630,8 +640,14 @@
// Before starting tethering, turn off supplicant for scan mode
if (msg.arg1 == 1) {
mSettingsStore.setWifiSavedState(WifiSettingsStore.WIFI_DISABLED);
- deferMessage(obtainMessage(msg.what, msg.arg1, 1, msg.obj));
- transitionTo(mApStaDisabledState);
+
+ mWifiStateMachine.setHostApRunning((SoftApModeConfiguration) msg.obj, true);
+ mWifiStateMachinePrime.enterSoftAPMode((SoftApModeConfiguration) msg.obj);
+ transitionTo(mApEnabledState);
+ // we should just go directly to ApEnabled since we will kill interfaces
+ // from WSMP
+ //deferMessage(obtainMessage(msg.what, msg.arg1, 1, msg.obj));
+ //transitionTo(mApStaDisabledState);
}
break;
case CMD_DEFERRED_TOGGLE:
@@ -701,22 +717,26 @@
case CMD_AIRPLANE_TOGGLED:
if (mSettingsStore.isAirplaneModeOn()) {
mWifiStateMachine.setHostApRunning(null, false);
+ mWifiStateMachinePrime.disableWifi();
mPendingState = mApStaDisabledState;
}
break;
case CMD_WIFI_TOGGLED:
if (mSettingsStore.isWifiToggleEnabled()) {
mWifiStateMachine.setHostApRunning(null, false);
+ mWifiStateMachinePrime.disableWifi();
mPendingState = mDeviceActiveState;
}
break;
case CMD_SET_AP:
if (msg.arg1 == 0) {
mWifiStateMachine.setHostApRunning(null, false);
+ mWifiStateMachinePrime.disableWifi();
mPendingState = getNextWifiState();
}
break;
case CMD_AP_STOPPED:
+ mWifiStateMachine.setHostApRunning(null, false);
if (mPendingState == null) {
/**
* Stop triggered internally, either tether notification
@@ -736,10 +756,12 @@
case CMD_EMERGENCY_MODE_CHANGED:
if (msg.arg1 == 1) {
mWifiStateMachine.setHostApRunning(null, false);
+ mWifiStateMachinePrime.disableWifi();
mPendingState = mEcmState;
}
break;
case CMD_AP_START_FAILURE:
+ mWifiStateMachine.setHostApRunning(null, false);
transitionTo(getNextWifiState());
break;
default:
diff --git a/service/java/com/android/server/wifi/WifiCountryCode.java b/service/java/com/android/server/wifi/WifiCountryCode.java
index 66a035f..a9cbed6 100644
--- a/service/java/com/android/server/wifi/WifiCountryCode.java
+++ b/service/java/com/android/server/wifi/WifiCountryCode.java
@@ -19,6 +19,9 @@
import android.text.TextUtils;
import android.util.Log;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
/**
* Provide functions for making changes to WiFi country code.
* This Country Code is from MCC or phone default setting. This class sends Country Code
@@ -167,6 +170,21 @@
return pickCountryCode();
}
+ /**
+ * Method to dump the current state of this WifiCounrtyCode object.
+ */
+ public synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (mCurrentCountryCode != null) {
+ pw.println("CountryCode sent to driver: " + mCurrentCountryCode);
+ } else {
+ if (pickCountryCode() != null) {
+ pw.println("CountryCode: " + pickCountryCode() + " was not sent to driver");
+ } else {
+ pw.println("CountryCode was not initialized");
+ }
+ }
+ }
+
private void updateCountryCode() {
if (DBG) Log.d(TAG, "Update country code");
String country = pickCountryCode();
diff --git a/service/java/com/android/server/wifi/WifiDiagnostics.java b/service/java/com/android/server/wifi/WifiDiagnostics.java
index 921faa3..30294bd 100644
--- a/service/java/com/android/server/wifi/WifiDiagnostics.java
+++ b/service/java/com/android/server/wifi/WifiDiagnostics.java
@@ -454,6 +454,10 @@
return false;
}
+ if (!isVerboseLoggingEnabled()) {
+ return false;
+ }
+
for (WifiNative.RingBufferStatus buffer : mRingBuffers){
if ((buffer.flag & RING_BUFFER_FLAG_HAS_PER_PACKET_ENTRIES) != 0) {
diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java
index 4b8e682..c2806d8 100644
--- a/service/java/com/android/server/wifi/WifiInjector.java
+++ b/service/java/com/android/server/wifi/WifiInjector.java
@@ -16,14 +16,13 @@
package com.android.server.wifi;
+import android.annotation.NonNull;
import android.app.ActivityManager;
import android.content.Context;
import android.net.NetworkKey;
import android.net.NetworkScoreManager;
-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;
@@ -84,8 +83,8 @@
private final SupplicantP2pIfaceHal mSupplicantP2pIfaceHal;
private final WifiVendorHal mWifiVendorHal;
private final WifiStateMachine mWifiStateMachine;
+ private final WifiStateMachinePrime mWifiStateMachinePrime;
private final WifiSettingsStore mSettingsStore;
- private final WifiCertManager mCertManager;
private final OpenNetworkNotifier mOpenNetworkNotifier;
private final WifiLockManager mLockManager;
private final WifiController mWifiController;
@@ -116,11 +115,14 @@
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 INetworkManagementService mNwManagementService;
private final boolean mUseRealLogger;
@@ -162,14 +164,16 @@
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);
mWificondControl = new WificondControl(this, mWifiMonitor,
new CarrierNetworkConfig(mContext));
+ mNwManagementService = INetworkManagementService.Stub.asInterface(
+ ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
mWifiNative = new WifiNative(SystemProperties.get("wifi.interface", "wlan0"),
- mWifiVendorHal, mSupplicantStaIfaceHal, mWificondControl);
+ mWifiVendorHal, mSupplicantStaIfaceHal, mWificondControl, mNwManagementService);
mWifiP2pMonitor = new WifiP2pMonitor(this);
mSupplicantP2pIfaceHal = new SupplicantP2pIfaceHal(mWifiP2pMonitor);
mWifiP2pNative = new WifiP2pNative(SystemProperties.get("wifi.direct.interface", "p2p0"),
@@ -223,15 +227,23 @@
wifiStateMachineLooper, UserManager.get(mContext),
this, mBackupManagerProxy, mCountryCode, mWifiNative,
new WrongPasswordNotifier(mContext, mFrameworkFacade));
- mCertManager = new WifiCertManager(mContext);
+ IBinder b = mFrameworkFacade.getService(Context.NETWORKMANAGEMENT_SERVICE);
+ INetworkManagementService networkManagementService =
+ INetworkManagementService.Stub.asInterface(b);
+ mWifiStateMachinePrime = new WifiStateMachinePrime(this, wifiStateMachineLooper,
+ mWifiNative, networkManagementService);
mOpenNetworkNotifier = new OpenNetworkNotifier(mContext,
mWifiStateMachineHandlerThread.getLooper(), mFrameworkFacade, mClock, mWifiMetrics,
mWifiConfigManager, mWifiConfigStore, mWifiStateMachine,
new OpenNetworkRecommender(),
new ConnectToNetworkNotificationBuilder(mContext, mFrameworkFacade));
+ mWakeupController = new WakeupController(mContext,
+ mWifiStateMachineHandlerThread.getLooper(), new WakeupLock(mWifiConfigManager),
+ mWifiConfigManager, mWifiConfigStore, this, mFrameworkFacade);
mLockManager = new WifiLockManager(mContext, BatteryStatsService.getService());
mWifiController = new WifiController(mContext, mWifiStateMachine, mSettingsStore,
- mLockManager, mWifiServiceHandlerThread.getLooper(), mFrameworkFacade);
+ mLockManager, mWifiServiceHandlerThread.getLooper(), mFrameworkFacade,
+ mWifiStateMachinePrime);
mSelfRecovery = new SelfRecovery(mWifiController, mClock);
mWifiLastResortWatchdog = new WifiLastResortWatchdog(mSelfRecovery, mWifiMetrics);
mWifiMulticastLockManager = new WifiMulticastLockManager(mWifiStateMachine,
@@ -252,6 +264,17 @@
return sWifiInjector;
}
+ /**
+ * Enable verbose logging in Injector objects. Called from the WifiServiceImpl (based on
+ * binder call).
+ */
+ public void enableVerboseLogging(int verbose) {
+ mWifiLastResortWatchdog.enableVerboseLogging(verbose);
+ mWifiBackupRestore.enableVerboseLogging(verbose);
+ mHalDeviceManager.enableVerboseLogging(verbose);
+ LogcatLog.enableVerboseLogging(verbose);
+ }
+
public UserManager getUserManager() {
return UserManager.get(mContext);
}
@@ -296,12 +319,12 @@
return mWifiStateMachine;
}
- public WifiSettingsStore getWifiSettingsStore() {
- return mSettingsStore;
+ public WifiStateMachinePrime getWifiStateMachinePrime() {
+ return mWifiStateMachinePrime;
}
- public WifiCertManager getWifiCertManager() {
- return mCertManager;
+ public WifiSettingsStore getWifiSettingsStore() {
+ return mSettingsStore;
}
public WifiLockManager getWifiLockManager() {
@@ -348,6 +371,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);
@@ -368,18 +395,15 @@
* @param nmService NetworkManagementService allowing SoftApManager to listen for interface
* changes
* @param listener listener for SoftApManager
- * @param apInterface network interface to start hostapd against
- * @param config softAp WifiConfiguration
+ * @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(),
- mWifiNative, mCountryCode.getCountryCode(),
- listener, apInterface, nmService,
- mWifiApConfigStore, config, mWifiMetrics);
+ @NonNull SoftApModeConfiguration config) {
+ return new SoftApManager(mContext, mWifiStateMachineHandlerThread.getLooper(),
+ mFrameworkFacade, mWifiNative, mCountryCode.getCountryCode(), listener,
+ nmService, mWifiApConfigStore, config, mWifiMetrics);
}
/**
@@ -455,6 +479,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/WifiLinkLayerStats.java b/service/java/com/android/server/wifi/WifiLinkLayerStats.java
new file mode 100644
index 0000000..0c58670
--- /dev/null
+++ b/service/java/com/android/server/wifi/WifiLinkLayerStats.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2014 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 java.util.Arrays;
+
+/**
+ * A class representing link layer statistics collected over a Wifi Interface.
+ */
+
+/**
+ * {@hide}
+ */
+public class WifiLinkLayerStats {
+
+ /** Number of beacons received from our own AP */
+ public int beacon_rx;
+
+ /** RSSI of management frames */
+ public int rssi_mgmt;
+
+ /* Packet counters */
+
+ /** WME Best Effort Access Category received mpdu */
+ public long rxmpdu_be;
+ /** WME Best Effort Access Category transmitted mpdu */
+ public long txmpdu_be;
+ /** WME Best Effort Access Category lost mpdu */
+ public long lostmpdu_be;
+ /** WME Best Effort Access Category number of transmission retries */
+ public long retries_be;
+
+ /** WME Background Access Category received mpdu */
+ public long rxmpdu_bk;
+ /** WME Background Access Category transmitted mpdu */
+ public long txmpdu_bk;
+ /** WME Background Access Category lost mpdu */
+ public long lostmpdu_bk;
+ /** WME Background Access Category number of transmission retries */
+ public long retries_bk;
+
+ /** WME Video Access Category received mpdu */
+ public long rxmpdu_vi;
+ /** WME Video Access Category transmitted mpdu */
+ public long txmpdu_vi;
+ /** WME Video Access Category lost mpdu */
+ public long lostmpdu_vi;
+ /** WME Video Access Category number of transmission retries */
+ public long retries_vi;
+
+ /** WME Voice Access Category received mpdu */
+ public long rxmpdu_vo;
+ /** WME Voice Access Category transmitted mpdu */
+ public long txmpdu_vo;
+ /** WME Voice Access Category lost mpdu */
+ public long lostmpdu_vo;
+ /** WME Voice Access Category number of transmission retries */
+ public long retries_vo;
+
+ /**
+ * Cumulative milliseconds when radio is awake
+ */
+ public int on_time;
+ /**
+ * Cumulative milliseconds of active transmission
+ */
+ public int tx_time;
+ /**
+ * Cumulative milliseconds per level of active transmission
+ */
+ public int[] tx_time_per_level;
+ /**
+ * Cumulative milliseconds of active receive
+ */
+ public int rx_time;
+ /**
+ * Cumulative milliseconds when radio is awake due to scan
+ */
+ public int on_time_scan;
+
+ /**
+ * TimeStamp - absolute milliseconds from boot when these stats were sampled.
+ */
+ public long timeStampInMs;
+
+ @Override
+ public String toString() {
+ StringBuilder sbuf = new StringBuilder();
+ sbuf.append(" WifiLinkLayerStats: ").append('\n');
+
+ sbuf.append(" my bss beacon rx: ").append(Integer.toString(this.beacon_rx)).append('\n');
+ sbuf.append(" RSSI mgmt: ").append(Integer.toString(this.rssi_mgmt)).append('\n');
+ sbuf.append(" BE : ").append(" rx=").append(Long.toString(this.rxmpdu_be))
+ .append(" tx=").append(Long.toString(this.txmpdu_be))
+ .append(" lost=").append(Long.toString(this.lostmpdu_be))
+ .append(" retries=").append(Long.toString(this.retries_be)).append('\n');
+ sbuf.append(" BK : ").append(" rx=").append(Long.toString(this.rxmpdu_bk))
+ .append(" tx=").append(Long.toString(this.txmpdu_bk))
+ .append(" lost=").append(Long.toString(this.lostmpdu_bk))
+ .append(" retries=").append(Long.toString(this.retries_bk)).append('\n');
+ sbuf.append(" VI : ").append(" rx=").append(Long.toString(this.rxmpdu_vi))
+ .append(" tx=").append(Long.toString(this.txmpdu_vi))
+ .append(" lost=").append(Long.toString(this.lostmpdu_vi))
+ .append(" retries=").append(Long.toString(this.retries_vi)).append('\n');
+ sbuf.append(" VO : ").append(" rx=").append(Long.toString(this.rxmpdu_vo))
+ .append(" tx=").append(Long.toString(this.txmpdu_vo))
+ .append(" lost=").append(Long.toString(this.lostmpdu_vo))
+ .append(" retries=").append(Long.toString(this.retries_vo)).append('\n');
+ sbuf.append(" on_time : ").append(Integer.toString(this.on_time))
+ .append(" rx_time=").append(Integer.toString(this.rx_time))
+ .append(" scan_time=").append(Integer.toString(this.on_time_scan)).append('\n')
+ .append(" tx_time=").append(Integer.toString(this.tx_time))
+ .append(" tx_time_per_level=" + Arrays.toString(tx_time_per_level));
+ sbuf.append(" ts=" + timeStampInMs);
+ return sbuf.toString();
+ }
+
+}
diff --git a/service/java/com/android/server/wifi/WifiLockManager.java b/service/java/com/android/server/wifi/WifiLockManager.java
index fe193f0..df9586f 100644
--- a/service/java/com/android/server/wifi/WifiLockManager.java
+++ b/service/java/com/android/server/wifi/WifiLockManager.java
@@ -71,7 +71,7 @@
if (!isValidLockMode(lockMode)) {
throw new IllegalArgumentException("lockMode =" + lockMode);
}
- if (ws == null || ws.size() == 0) {
+ if (ws == null || ws.isEmpty()) {
ws = new WorkSource(Binder.getCallingUid());
} else {
mContext.enforceCallingOrSelfPermission(
@@ -144,15 +144,23 @@
}
WorkSource newWorkSource;
- if (ws == null || ws.size() == 0) {
+ if (ws == null || ws.isEmpty()) {
newWorkSource = new WorkSource(Binder.getCallingUid());
} else {
// Make a copy of the WorkSource before adding it to the WakeLock
newWorkSource = new WorkSource(ws);
}
+ if (mVerboseLoggingEnabled) {
+ Slog.d(TAG, "updateWifiLockWakeSource: " + wl + ", newWorkSource=" + newWorkSource);
+ }
+
long ident = Binder.clearCallingIdentity();
try {
+ // TODO: Introduce a noteFullWifiLockChangedFromSource() so that this logic can be
+ // handled properly in BatteryStats rather than here. This would ensure there are no
+ // "holes" in the reported data due to a "release" event occurring before an
+ // "acquire" event.
mBatteryStats.noteFullWifiLockReleasedFromSource(wl.mWorkSource);
wl.mWorkSource = newWorkSource;
mBatteryStats.noteFullWifiLockAcquiredFromSource(wl.mWorkSource);
@@ -323,7 +331,8 @@
}
public String toString() {
- return "WifiLock{" + this.mTag + " type=" + this.mMode + " uid=" + mUid + "}";
+ return "WifiLock{" + this.mTag + " type=" + this.mMode + " uid=" + mUid
+ + " workSource=" + mWorkSource + "}";
}
}
}
diff --git a/service/java/com/android/server/wifi/WifiMetrics.java b/service/java/com/android/server/wifi/WifiMetrics.java
index 7254ad4..4e277a1 100644
--- a/service/java/com/android/server/wifi/WifiMetrics.java
+++ b/service/java/com/android/server/wifi/WifiMetrics.java
@@ -31,6 +31,7 @@
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;
@@ -41,8 +42,10 @@
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;
@@ -80,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,
@@ -92,11 +97,14 @@
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;
@@ -167,6 +175,10 @@
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();
@@ -479,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;
@@ -1055,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) {
@@ -1067,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);
+ }
}
}
@@ -1106,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() {
@@ -1634,6 +1783,40 @@
+ 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);
}
}
}
@@ -1906,6 +2089,19 @@
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;
}
}
@@ -1966,6 +2162,9 @@
mObservedHotspotR2EssInScanHistogram.clear();
mObservedHotspotR1ApsPerEssInScanHistogram.clear();
mObservedHotspotR2ApsPerEssInScanHistogram.clear();
+ mSoftApEventListTethered.clear();
+ mSoftApEventListLocalOnly.clear();
+ mWpsMetrics.clear();
}
}
@@ -1984,6 +2183,7 @@
public void setWifiState(int wifiState) {
synchronized (mLock) {
mWifiState = wifiState;
+ mWifiWins = (wifiState == WifiMetricsProto.WifiLog.WIFI_ASSOCIATED);
}
}
@@ -2089,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);
@@ -2109,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();
@@ -2268,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;
@@ -2275,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));
@@ -2337,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
diff --git a/service/java/com/android/server/wifi/WifiNative.java b/service/java/com/android/server/wifi/WifiNative.java
index 5b12a36..666f2b5 100644
--- a/service/java/com/android/server/wifi/WifiNative.java
+++ b/service/java/com/android/server/wifi/WifiNative.java
@@ -16,7 +16,10 @@
package com.android.server.wifi;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.net.InterfaceConfiguration;
import android.net.apf.ApfCapabilities;
import android.net.wifi.IApInterface;
import android.net.wifi.IClientInterface;
@@ -24,10 +27,12 @@
import android.net.wifi.RttManager.ResponderConfig;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiLinkLayerStats;
import android.net.wifi.WifiScanner;
import android.net.wifi.WifiWakeReasonAndCounts;
+import android.os.INetworkManagementService;
+import android.os.RemoteException;
import android.os.SystemClock;
+import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
@@ -35,10 +40,13 @@
import com.android.internal.annotations.Immutable;
import com.android.internal.util.HexDump;
import com.android.server.connectivity.KeepalivePacketData;
+import com.android.server.net.BaseNetworkObserver;
import com.android.server.wifi.util.FrameParser;
import java.io.PrintWriter;
import java.io.StringWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException;
@@ -47,12 +55,14 @@
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.TimeZone;
-
/**
* Native calls for bring up/shut down of the supplicant daemon and for
* sending requests to the supplicant daemon
@@ -65,14 +75,19 @@
private final SupplicantStaIfaceHal mSupplicantStaIfaceHal;
private final WifiVendorHal mWifiVendorHal;
private final WificondControl mWificondControl;
+ private final INetworkManagementService mNwManagementService;
+ // TODO(b/69426063): Remove interfaceName from constructor once WifiStateMachine switches over
+ // to the new interface management methods.
public WifiNative(String interfaceName, WifiVendorHal vendorHal,
- SupplicantStaIfaceHal staIfaceHal, WificondControl condControl) {
+ SupplicantStaIfaceHal staIfaceHal, WificondControl condControl,
+ INetworkManagementService nwService) {
mTAG = "WifiNative-" + interfaceName;
mInterfaceName = interfaceName;
mWifiVendorHal = vendorHal;
mSupplicantStaIfaceHal = staIfaceHal;
mWificondControl = condControl;
+ mNwManagementService = nwService;
}
public String getInterfaceName() {
@@ -105,12 +120,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 +141,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);
}
@@ -152,6 +167,598 @@
}
}
+ /**
+ * TODO(b/69426063): NEW API Surface for interface management. This will eventually
+ * deprecate the other interface management API's above. But, for now there will be
+ * some duplication to ease transition.
+ */
+ /**
+ * Meta-info about every iface that is active.
+ */
+ private static class Iface {
+ /** Type of ifaces possible */
+ public static final int IFACE_TYPE_AP = 0;
+ public static final int IFACE_TYPE_STA = 1;
+
+ @IntDef({IFACE_TYPE_AP, IFACE_TYPE_STA})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface IfaceType{}
+
+ /** Identifier allocated for the interface */
+ public final int id;
+ /** Type of the iface: STA or AP */
+ public final @IfaceType int type;
+ /** Name of the interface */
+ public String name;
+ /** External iface destroyed listener for the iface */
+ public InterfaceCallback externalListener;
+ /** Network observer registered for this interface */
+ public NetworkObserverInternal networkObserver;
+
+ Iface(int id, @Iface.IfaceType int type) {
+ this.id = id;
+ this.type = type;
+ }
+ }
+
+ /**
+ * Iface Management entity. This class maintains list of all the active ifaces.
+ */
+ private static class IfaceManager {
+ /** Integer to allocate for the next iface being created */
+ private int mNextId;
+ /** Map of the id to the iface structure */
+ private HashMap<Integer, Iface> mIfaces = new HashMap<>();
+
+ /** Allocate a new iface for the given type */
+ private Iface allocateIface(@Iface.IfaceType int type) {
+ Iface iface = new Iface(mNextId, type);
+ mIfaces.put(mNextId, iface);
+ mNextId++;
+ return iface;
+ }
+
+ /** Remove the iface using the provided id */
+ private Iface removeIface(int id) {
+ return mIfaces.remove(id);
+ }
+
+ /** Lookup the iface using the provided id */
+ private Iface getIface(int id) {
+ return mIfaces.get(id);
+ }
+
+ /** Lookup the iface using the provided name */
+ private Iface getIface(@NonNull String ifaceName) {
+ for (Iface iface : mIfaces.values()) {
+ if (TextUtils.equals(iface.name, ifaceName)) {
+ return iface;
+ }
+ }
+ return null;
+ }
+
+ /** Iterator to use for deleting all the ifaces while performing teardown on each of them */
+ private Iterator<Integer> getIfaceIdIter() {
+ return mIfaces.keySet().iterator();
+ }
+
+ /** Checks if there are any iface active. */
+ private boolean hasAnyIface() {
+ return !mIfaces.isEmpty();
+ }
+
+ /** Checks if there are any iface of the given type active. */
+ private boolean hasAnyIfaceOfType(@Iface.IfaceType int type) {
+ for (Iface iface : mIfaces.values()) {
+ if (iface.type == type) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /** Checks if there are any STA iface active. */
+ private boolean hasAnyStaIface() {
+ return hasAnyIfaceOfType(Iface.IFACE_TYPE_STA);
+ }
+
+ /** Checks if there are any AP iface active. */
+ private boolean hasAnyApIface() {
+ return hasAnyIfaceOfType(Iface.IFACE_TYPE_AP);
+ }
+ }
+
+ private Object mLock = new Object();
+ private final IfaceManager mIfaceMgr = new IfaceManager();
+ private HashSet<StatusListener> mStatusListeners = new HashSet<>();
+
+ /** Helper method invoked to start supplicant if there were no ifaces */
+ private boolean startHal() {
+ synchronized (mLock) {
+ if (!mIfaceMgr.hasAnyIface()) {
+ if (!mWifiVendorHal.startVendorHal()) {
+ Log.e(mTAG, "Failed to start vendor HAL");
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ /** Helper method invoked to stop HAL if there are no more ifaces */
+ private void stopHalAndWificondIfNecessary() {
+ synchronized (mLock) {
+ if (!mIfaceMgr.hasAnyIface()) {
+ if (!mWificondControl.tearDownInterfaces()) {
+ Log.e(mTAG, "Failed to teardown ifaces from wificond");
+ }
+ mWifiVendorHal.stopVendorHal();
+ }
+ }
+ }
+
+ private static final int CONNECT_TO_SUPPLICANT_RETRY_INTERVAL_MS = 100;
+ private static final int CONNECT_TO_SUPPLICANT_RETRY_TIMES = 50;
+ /**
+ * This method is called to wait for establishing connection to wpa_supplicant.
+ *
+ * @return true if connection is established, false otherwise.
+ */
+ private boolean waitForSupplicantConnection() {
+ // Start initialization if not already started.
+ if (!mSupplicantStaIfaceHal.isInitializationStarted()
+ && !mSupplicantStaIfaceHal.initialize()) {
+ return false;
+ }
+ boolean connected = false;
+ int connectTries = 0;
+ while (!connected && connectTries++ < CONNECT_TO_SUPPLICANT_RETRY_TIMES) {
+ // Check if the initialization is complete.
+ connected = mSupplicantStaIfaceHal.isInitializationComplete();
+ if (connected) {
+ break;
+ }
+ try {
+ Thread.sleep(CONNECT_TO_SUPPLICANT_RETRY_INTERVAL_MS);
+ } catch (InterruptedException ignore) {
+ }
+ }
+ return connected;
+ }
+
+ /** Helper method invoked to start supplicant if there were no STA ifaces */
+ private boolean startSupplicant() {
+ synchronized (mLock) {
+ if (!mIfaceMgr.hasAnyStaIface()) {
+ if (!mWificondControl.enableSupplicant()) {
+ Log.e(mTAG, "Failed to enable supplicant");
+ return false;
+ }
+ if (!waitForSupplicantConnection()) {
+ Log.e(mTAG, "Failed to connect to supplicant");
+ return false;
+ }
+ if (!mSupplicantStaIfaceHal.registerDeathHandler(new DeathHandlerInternal())) {
+ Log.e(mTAG, "Failed to register supplicant death handler");
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ /** Helper method invoked to stop supplicant if there are no more STA ifaces */
+ private void stopSupplicantIfNecessary() {
+ synchronized (mLock) {
+ if (!mIfaceMgr.hasAnyStaIface()) {
+ if (!mSupplicantStaIfaceHal.deregisterDeathHandler()) {
+ Log.e(mTAG, "Failed to deregister supplicant death handler");
+ }
+ if (!mWificondControl.disableSupplicant()) {
+ Log.e(mTAG, "Failed to disable supplicant");
+ }
+ }
+ }
+ }
+
+ /** Helper method to register a network observer and return it */
+ private boolean registerNetworkObserver(@NonNull NetworkObserverInternal observer) {
+ try {
+ mNwManagementService.registerObserver(observer);
+ } catch (RemoteException e) {
+ return false;
+ }
+ return true;
+ }
+
+ /** Helper method to register a network observer and return it */
+ private boolean unregisterNetworkObserver(@NonNull NetworkObserverInternal observer) {
+ try {
+ mNwManagementService.unregisterObserver(observer);
+ } catch (RemoteException e) {
+ return false;
+ }
+ return true;
+ }
+
+ /** Helper method invoked to teardown client iface and perform necessary cleanup */
+ private void onClientInterfaceDestroyed(@NonNull Iface iface) {
+ synchronized (mLock) {
+ if (!unregisterNetworkObserver(iface.networkObserver)) {
+ Log.e(mTAG, "Failed to unregister network observer for iface=" + iface.name);
+ }
+ if (!mSupplicantStaIfaceHal.teardownIface(iface.name)) {
+ Log.e(mTAG, "Failed to teardown iface in supplicant=" + iface.name);
+ }
+ if (!mWificondControl.tearDownClientInterface(iface.name)) {
+ Log.e(mTAG, "Failed to teardown iface in wificond=" + iface.name);
+ }
+ stopSupplicantIfNecessary();
+ stopHalAndWificondIfNecessary();
+ }
+ }
+
+ /** Helper method invoked to teardown softAp iface and perform necessary cleanup */
+ private void onSoftApInterfaceDestroyed(@NonNull Iface iface) {
+ synchronized (mLock) {
+ if (!unregisterNetworkObserver(iface.networkObserver)) {
+ Log.e(mTAG, "Failed to unregister network observer for iface=" + iface.name);
+ }
+ if (!mWificondControl.stopSoftAp(iface.name)) {
+ Log.e(mTAG, "Failed to stop softap on iface=" + iface.name);
+ }
+ if (!mWificondControl.tearDownSoftApInterface(iface.name)) {
+ Log.e(mTAG, "Failed to teardown iface in wificond=" + iface.name);
+ }
+ stopHalAndWificondIfNecessary();
+ }
+ }
+
+ /** Helper method invoked to teardown iface and perform necessary cleanup */
+ private void onInterfaceDestroyed(@NonNull Iface iface) {
+ synchronized (mLock) {
+ if (iface.type == Iface.IFACE_TYPE_STA) {
+ onClientInterfaceDestroyed(iface);
+ } else if (iface.type == Iface.IFACE_TYPE_AP) {
+ onSoftApInterfaceDestroyed(iface);
+ }
+ // Invoke the external callback.
+ iface.externalListener.onDestroyed(iface.name);
+ }
+ }
+
+ /**
+ * Callback to be invoked by HalDeviceManager when an interface is destroyed.
+ */
+ private class InterfaceDestoyedListenerInternal
+ implements HalDeviceManager.InterfaceDestroyedListener {
+ /** Identifier allocated for the interface */
+ private final int mInterfaceId;
+
+ InterfaceDestoyedListenerInternal(int ifaceId) {
+ mInterfaceId = ifaceId;
+ }
+
+ @Override
+ public void onDestroyed(@NonNull String ifaceName) {
+ synchronized (mLock) {
+ final Iface iface = mIfaceMgr.removeIface(mInterfaceId);
+ if (iface == null) {
+ Log.e(mTAG, "Received iface destroyed notification on an invalid iface="
+ + ifaceName);
+ return;
+ }
+ onInterfaceDestroyed(iface);
+ Log.i(mTAG, "Successfully torn down iface=" + ifaceName);
+ }
+ }
+ }
+
+ /**
+ * Common death handler for any of the lower layer daemons.
+ */
+ private class DeathHandlerInternal implements VendorHalDeathEventHandler,
+ SupplicantDeathEventHandler, WificondDeathEventHandler {
+ @Override
+ public void onDeath() {
+ synchronized (mLock) {
+ Log.i(mTAG, "One of the daemons died. Tearing down everything");
+ Iterator<Integer> ifaceIdIter = mIfaceMgr.getIfaceIdIter();
+ while (ifaceIdIter.hasNext()) {
+ Iface iface = mIfaceMgr.getIface(ifaceIdIter.next());
+ ifaceIdIter.remove();
+ onInterfaceDestroyed(iface);
+ Log.i(mTAG, "Successfully torn down iface=" + iface.name);
+ }
+ for (StatusListener listener : mStatusListeners) {
+ listener.onStatusChanged(false);
+ }
+ // TODO(70572148): Do we need to wait to mark the system ready again?
+ for (StatusListener listener : mStatusListeners) {
+ listener.onStatusChanged(true);
+ }
+ }
+ }
+ }
+
+ /**
+ * Network observer to use for all interface up/down notifications.
+ */
+ private class NetworkObserverInternal extends BaseNetworkObserver {
+ /** Identifier allocated for the interface */
+ private final int mInterfaceId;
+
+ NetworkObserverInternal(int id) {
+ mInterfaceId = id;
+ }
+
+ @Override
+ public void interfaceLinkStateChanged(String ifaceName, boolean isUp) {
+ synchronized (mLock) {
+ Log.i(mTAG, "Interface link state changed=" + ifaceName + ", isUp=" + isUp);
+ final Iface iface = mIfaceMgr.getIface(mInterfaceId);
+ if (iface == null) {
+ Log.e(mTAG, "Received iface up/down notification on an invalid iface="
+ + ifaceName);
+ return;
+ }
+ if (isUp) {
+ iface.externalListener.onUp(ifaceName);
+ } else {
+ iface.externalListener.onDown(ifaceName);
+ }
+ }
+ }
+ }
+
+ /**
+ * Initialize the native modules.
+ *
+ * @return true on success, false otherwise.
+ */
+ public boolean initialize() {
+ synchronized (mLock) {
+ if (!mWifiVendorHal.initialize(new DeathHandlerInternal())) {
+ Log.e(mTAG, "Failed to initialize vendor HAL");
+ return false;
+ }
+ if (!mWificondControl.registerDeathHandler(new DeathHandlerInternal())) {
+ Log.e(mTAG, "Failed to initialize wificond");
+ return false;
+ }
+ return true;
+ }
+ }
+
+ /**
+ * Callback to notify when the status of one of the native daemons
+ * (wificond, wpa_supplicant & vendor HAL) changes.
+ */
+ public interface StatusListener {
+ /**
+ * @param allReady Indicates if all the native daemons are ready for operation or not.
+ */
+ void onStatusChanged(boolean allReady);
+ }
+
+ /**
+ * Register a StatusListener to get notified about any status changes from the native daemons.
+ *
+ * It is safe to re-register the same callback object - duplicates are detected and only a
+ * single copy kept.
+ *
+ * @param listener StatusListener listener object.
+ */
+ public void registerStatusListener(@NonNull StatusListener listener) {
+ mStatusListeners.add(listener);
+ }
+
+ /**
+ * Callback to notify when the associated interface is destroyed, up or down.
+ */
+ public interface InterfaceCallback {
+ /**
+ * Interface destroyed by HalDeviceManager.
+ *
+ * @param ifaceName Name of the iface.
+ */
+ void onDestroyed(String ifaceName);
+
+ /**
+ * Interface is up.
+ *
+ * @param ifaceName Name of the iface.
+ */
+ void onUp(String ifaceName);
+
+ /**
+ * Interface is down.
+ *
+ * @param ifaceName Name of the iface.
+ */
+ void onDown(String ifaceName);
+ }
+
+ private void initializeNwParamsForClientInterface(@NonNull String ifaceName) {
+ try {
+ // A runtime crash or shutting down AP mode can leave
+ // IP addresses configured, and this affects
+ // connectivity when supplicant starts up.
+ // Ensure we have no IP addresses before a supplicant start.
+ mNwManagementService.clearInterfaceAddresses(ifaceName);
+
+ // Set privacy extensions
+ mNwManagementService.setInterfaceIpv6PrivacyExtensions(ifaceName, true);
+
+ // IPv6 is enabled only as long as access point is connected since:
+ // - IPv6 addresses and routes stick around after disconnection
+ // - kernel is unaware when connected and fails to start IPv6 negotiation
+ // - kernel can start autoconfiguration when 802.1x is not complete
+ mNwManagementService.disableIpv6(ifaceName);
+ } catch (RemoteException re) {
+ Log.e(mTAG, "Unable to change interface settings: " + re);
+ } catch (IllegalStateException ie) {
+ Log.e(mTAG, "Unable to change interface settings: " + ie);
+ }
+ }
+
+ /**
+ * Setup an interface for Client mode operations.
+ *
+ * This method configures an interface in STA mode in all the native daemons
+ * (wificond, wpa_supplicant & vendor HAL).
+ *
+ * @param interfaceCallback Associated callback for notifying status changes for the iface.
+ * @return Returns the name of the allocated interface, will be null on failure.
+ */
+ public String setupInterfaceForClientMode(@NonNull InterfaceCallback interfaceCallback) {
+ synchronized (mLock) {
+ if (!startHal()) {
+ Log.e(mTAG, "Failed to start Hal");
+ return null;
+ }
+ if (!startSupplicant()) {
+ Log.e(mTAG, "Failed to start supplicant");
+ return null;
+ }
+ Iface iface = mIfaceMgr.allocateIface(Iface.IFACE_TYPE_STA);
+ if (iface == null) {
+ Log.e(mTAG, "Failed to allocate new STA iface");
+ return null;
+ }
+ iface.externalListener = interfaceCallback;
+ iface.name =
+ mWifiVendorHal.createStaIface(new InterfaceDestoyedListenerInternal(iface.id));
+ if (TextUtils.isEmpty(iface.name)) {
+ Log.e(mTAG, "Failed to create iface in vendor HAL");
+ mIfaceMgr.removeIface(iface.id);
+ return null;
+ }
+ if (mWificondControl.setupInterfaceForClientMode(iface.name) == null) {
+ Log.e(mTAG, "Failed to setup iface in wificond=" + iface.name);
+ teardownInterface(iface.name);
+ return null;
+ }
+ if (!mSupplicantStaIfaceHal.setupIface(iface.name)) {
+ Log.e(mTAG, "Failed to setup iface in supplicant=" + iface.name);
+ teardownInterface(iface.name);
+ return null;
+ }
+ iface.networkObserver = new NetworkObserverInternal(iface.id);
+ if (!registerNetworkObserver(iface.networkObserver)) {
+ Log.e(mTAG, "Failed to register network observer for iface=" + iface.name);
+ teardownInterface(iface.name);
+ return null;
+ }
+ initializeNwParamsForClientInterface(iface.name);
+ Log.i(mTAG, "Successfully setup iface=" + iface.name);
+ return iface.name;
+ }
+ }
+
+ /**
+ * Setup an interface for Soft AP mode operations.
+ *
+ * This method configures an interface in AP mode in all the native daemons
+ * (wificond, wpa_supplicant & vendor HAL).
+ *
+ * @param interfaceCallback Associated callback for notifying status changes for the iface.
+ * @return Returns the name of the allocated interface, will be null on failure.
+ */
+ public String setupInterfaceForSoftApMode(@NonNull InterfaceCallback interfaceCallback) {
+ synchronized (mLock) {
+ if (!startHal()) {
+ Log.e(mTAG, "Failed to start Hal");
+ return null;
+ }
+ Iface iface = mIfaceMgr.allocateIface(Iface.IFACE_TYPE_AP);
+ if (iface == null) {
+ Log.e(mTAG, "Failed to allocate new AP iface");
+ return null;
+ }
+ iface.externalListener = interfaceCallback;
+ iface.name =
+ mWifiVendorHal.createApIface(new InterfaceDestoyedListenerInternal(iface.id));
+ if (TextUtils.isEmpty(iface.name)) {
+ Log.e(mTAG, "Failed to create iface in vendor HAL");
+ mIfaceMgr.removeIface(iface.id);
+ return null;
+ }
+ if (mWificondControl.setupInterfaceForSoftApMode(iface.name) == null) {
+ Log.e(mTAG, "Failed to setup iface in wificond=" + iface.name);
+ teardownInterface(iface.name);
+ return null;
+ }
+ iface.networkObserver = new NetworkObserverInternal(iface.id);
+ if (!registerNetworkObserver(iface.networkObserver)) {
+ Log.e(mTAG, "Failed to register network observer for iface=" + iface.name);
+ teardownInterface(iface.name);
+ return null;
+ }
+ Log.i(mTAG, "Successfully setup iface=" + iface.name);
+ return iface.name;
+ }
+ }
+
+ /**
+ * Check if the interface is up or down.
+ *
+ * @param ifaceName Name of the interface.
+ * @return true if iface is up, false if it's down or on error.
+ */
+ public boolean isInterfaceUp(@NonNull String ifaceName) {
+ synchronized (mLock) {
+ final Iface iface = mIfaceMgr.getIface(ifaceName);
+ if (iface == null) {
+ Log.e(mTAG, "Trying to get iface state on invalid iface=" + ifaceName);
+ return false;
+ }
+ InterfaceConfiguration config = null;
+ try {
+ config = mNwManagementService.getInterfaceConfig(ifaceName);
+ } catch (RemoteException e) {
+ }
+ if (config == null) {
+ return false;
+ }
+ return config.isUp();
+ }
+ }
+
+ /**
+ * Teardown an interface in Client/AP mode.
+ *
+ * This method tears down the associated interface from all the native daemons
+ * (wificond, wpa_supplicant & vendor HAL).
+ *
+ * @param ifaceName Name of the interface.
+ */
+ public void teardownInterface(@NonNull String ifaceName) {
+ synchronized (mLock) {
+ final Iface iface = mIfaceMgr.getIface(ifaceName);
+ if (iface == null) {
+ Log.e(mTAG, "Trying to teardown an invalid iface=" + ifaceName);
+ return;
+ }
+ // Trigger the iface removal from HAL. The rest of the cleanup will be triggered
+ // from the interface destroyed callback.
+ // TODO(b/70521011): Figure out what to do for devices with no HAL.
+ if (iface.type == Iface.IFACE_TYPE_STA) {
+ if (!mWifiVendorHal.removeStaIface(ifaceName)) {
+ Log.e(mTAG, "Failed to remove iface in vendor HAL=" + ifaceName);
+ return;
+ }
+ } else if (iface.type == Iface.IFACE_TYPE_AP) {
+ if (!mWifiVendorHal.removeApIface(ifaceName)) {
+ Log.e(mTAG, "Failed to remove iface in vendor HAL=" + ifaceName);
+ return;
+ }
+ }
+ Log.i(mTAG, "Successfully initiated teardown for iface=" + ifaceName);
+ }
+ }
+
/********************************************************
* Wificond operations
********************************************************/
@@ -178,6 +785,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 +832,7 @@
* Returns null on failure.
*/
public SignalPollResult signalPoll() {
- return mWificondControl.signalPoll();
+ return mWificondControl.signalPoll(mInterfaceName);
}
/**
@@ -208,7 +841,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 +867,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 +876,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 +886,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 +895,7 @@
* @return true on success.
*/
public boolean startPnoScan(PnoSettings pnoSettings) {
- return mWificondControl.startPnoScan(pnoSettings);
+ return mWificondControl.startPnoScan(mInterfaceName, pnoSettings);
}
/**
@@ -253,7 +903,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 +941,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 +972,17 @@
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.
}
/**
@@ -298,7 +1000,7 @@
* @return true if request is sent successfully, false otherwise.
*/
public boolean reconnect() {
- return mSupplicantStaIfaceHal.reconnect();
+ return mSupplicantStaIfaceHal.reconnect(mInterfaceName);
}
/**
@@ -307,7 +1009,7 @@
* @return true if request is sent successfully, false otherwise.
*/
public boolean reassociate() {
- return mSupplicantStaIfaceHal.reassociate();
+ return mSupplicantStaIfaceHal.reassociate(mInterfaceName);
}
/**
@@ -316,7 +1018,7 @@
* @return true if request is sent successfully, false otherwise.
*/
public boolean disconnect() {
- return mSupplicantStaIfaceHal.disconnect();
+ return mSupplicantStaIfaceHal.disconnect(mInterfaceName);
}
/**
@@ -325,7 +1027,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 +1057,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 +1068,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 +1079,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 +1090,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 +1108,7 @@
* @return Whether the mode was successfully set.
*/
public boolean setBluetoothCoexistenceMode(int mode) {
- return mSupplicantStaIfaceHal.setBtCoexistenceMode(mode);
+ return mSupplicantStaIfaceHal.setBtCoexistenceMode(mInterfaceName, mode);
}
/**
@@ -418,7 +1120,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 +1131,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 +1141,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 +1152,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 +1166,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 +1176,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 +1186,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 +1196,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 +1215,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 +1234,7 @@
* @return true if succeeds, false otherwise.
*/
public boolean simAuthFailedResponse(int id) {
- return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimGsmAuthFailure();
+ return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimGsmAuthFailure(mInterfaceName);
}
/**
@@ -537,7 +1243,7 @@
* @return true if succeeds, false otherwise.
*/
public boolean umtsAuthFailedResponse(int id) {
- return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimUmtsAuthFailure();
+ return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimUmtsAuthFailure(mInterfaceName);
}
/**
@@ -547,7 +1253,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 +1263,7 @@
* @return anonymous identity string if succeeds, null otherwise.
*/
public String getEapAnonymousIdentity() {
- return mSupplicantStaIfaceHal.getCurrentNetworkEapAnonymousIdentity();
+ return mSupplicantStaIfaceHal.getCurrentNetworkEapAnonymousIdentity(mInterfaceName);
}
/**
@@ -567,7 +1274,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 +1283,7 @@
* @return true if request is sent successfully, false otherwise.
*/
public boolean cancelWps() {
- return mSupplicantStaIfaceHal.cancelWps();
+ return mSupplicantStaIfaceHal.cancelWps(mInterfaceName);
}
/**
@@ -586,7 +1293,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 +1303,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 +1313,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 +1323,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 +1333,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 +1343,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 +1353,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 +1362,7 @@
* @param enabled true to enable, false to disable.
*/
public void setPowerSave(boolean enabled) {
- mSupplicantStaIfaceHal.setPowerSave(enabled);
+ mSupplicantStaIfaceHal.setPowerSave(mInterfaceName, enabled);
}
/**
@@ -676,7 +1383,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 +1396,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 +1414,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 +1433,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 +1454,7 @@
* @return {@code true} if it succeeds, {@code false} otherwise
*/
public boolean removeAllNetworks() {
- return mSupplicantStaIfaceHal.removeAllNetworks();
+ return mSupplicantStaIfaceHal.removeAllNetworks(mInterfaceName);
}
/**
@@ -756,7 +1463,7 @@
* @return true if successful, false otherwise.
*/
public boolean setConfiguredNetworkBSSID(String bssid) {
- return mSupplicantStaIfaceHal.setCurrentNetworkBssid(bssid);
+ return mSupplicantStaIfaceHal.setCurrentNetworkBssid(mInterfaceName, bssid);
}
/**
@@ -779,7 +1486,8 @@
}
ArrayList<Integer> hs20SubtypeList = new ArrayList<>();
hs20SubtypeList.addAll(hs20Subtypes);
- return mSupplicantStaIfaceHal.initiateAnqpQuery(bssid, anqpIdList, hs20SubtypeList);
+ return mSupplicantStaIfaceHal.initiateAnqpQuery(
+ mInterfaceName, bssid, anqpIdList, hs20SubtypeList);
}
/**
@@ -793,7 +1501,7 @@
Log.e(mTAG, "Invalid arguments for Icon request.");
return false;
}
- return mSupplicantStaIfaceHal.initiateHs20IconQuery(bssid, fileName);
+ return mSupplicantStaIfaceHal.initiateHs20IconQuery(mInterfaceName, bssid, fileName);
}
/**
@@ -802,7 +1510,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 +1519,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 +1553,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 +1594,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 +1744,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 +1785,7 @@
* @return bitmask defined by WifiManager.WIFI_FEATURE_*
*/
public int getSupportedFeatureSet() {
- return mWifiVendorHal.getSupportedFeatureSet();
+ return mWifiVendorHal.getSupportedFeatureSet(mInterfaceName);
}
public static interface RttEventHandler {
@@ -1130,28 +1842,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 +1856,7 @@
* Get the APF (Android Packet Filter) capabilities of the device
*/
public ApfCapabilities getApfCapabilities() {
- return mWifiVendorHal.getApfCapabilities();
+ return mWifiVendorHal.getApfCapabilities(mInterfaceName);
}
/**
@@ -1175,7 +1866,7 @@
* @return true for success
*/
public boolean installPacketFilter(byte[] filter) {
- return mWifiVendorHal.installPacketFilter(filter);
+ return mWifiVendorHal.installPacketFilter(mInterfaceName, filter);
}
/**
@@ -1185,7 +1876,7 @@
* @return true for success
*/
public boolean setCountryCodeHal(String countryCode) {
- return mWifiVendorHal.setCountryCodeHal(countryCode);
+ return mWifiVendorHal.setCountryCodeHal(mInterfaceName, countryCode);
}
//---------------------------------------------------------------------------------
@@ -1525,7 +2216,7 @@
* @return true for success, false otherwise.
*/
public boolean startPktFateMonitoring() {
- return mWifiVendorHal.startPktFateMonitoring();
+ return mWifiVendorHal.startPktFateMonitoring(mInterfaceName);
}
/**
@@ -1534,14 +2225,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 +2251,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 +2262,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 +2279,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 +2303,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 +2321,7 @@
* @return true for success, false otherwise.
*/
public boolean getRoamingCapabilities(RoamingCapabilities capabilities) {
- return mWifiVendorHal.getRoamingCapabilities(capabilities);
+ return mWifiVendorHal.getRoamingCapabilities(mInterfaceName, capabilities);
}
/**
@@ -1644,7 +2336,7 @@
* @return error code returned from HAL.
*/
public int enableFirmwareRoaming(int state) {
- return mWifiVendorHal.enableFirmwareRoaming(state);
+ return mWifiVendorHal.enableFirmwareRoaming(mInterfaceName, state);
}
/**
@@ -1660,7 +2352,7 @@
*/
public boolean configureRoaming(RoamingConfig config) {
Log.d(mTAG, "configureRoaming ");
- return mWifiVendorHal.configureRoaming(config);
+ return mWifiVendorHal.configureRoaming(mInterfaceName, config);
}
/**
@@ -1669,7 +2361,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/WifiNetworkSelector.java b/service/java/com/android/server/wifi/WifiNetworkSelector.java
index 071fc07..46ded1c 100644
--- a/service/java/com/android/server/wifi/WifiNetworkSelector.java
+++ b/service/java/com/android/server/wifi/WifiNetworkSelector.java
@@ -152,9 +152,8 @@
boolean hasQualifiedRssi =
(wifiInfo.is24GHz() && (currentRssi > mThresholdQualifiedRssi24))
|| (wifiInfo.is5GHz() && (currentRssi > mThresholdQualifiedRssi5));
- // getTxSuccessRate() and getRxSuccessRate() returns the packet rate in per 5 seconds unit.
- boolean hasActiveStream = (wifiInfo.getTxSuccessRatePps() > mStayOnNetworkMinimumTxRate)
- || (wifiInfo.getRxSuccessRatePps() > mStayOnNetworkMinimumRxRate);
+ boolean hasActiveStream = (wifiInfo.txSuccessRate > mStayOnNetworkMinimumTxRate)
+ || (wifiInfo.rxSuccessRate > mStayOnNetworkMinimumRxRate);
if (hasQualifiedRssi && hasActiveStream) {
localLog("Stay on current network because of good RSSI and ongoing traffic");
return true;
diff --git a/service/java/com/android/server/wifi/WifiScoreReport.java b/service/java/com/android/server/wifi/WifiScoreReport.java
index 894d57c..1c258e1 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_pps,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..ce49e55 100644
--- a/service/java/com/android/server/wifi/WifiServiceImpl.java
+++ b/service/java/com/android/server/wifi/WifiServiceImpl.java
@@ -69,10 +69,10 @@
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConnectionStatistics;
import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiLinkLayerStats;
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;
@@ -97,6 +97,7 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
+import android.util.MutableInt;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
@@ -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;
@@ -175,8 +171,6 @@
final WifiSettingsStore mSettingsStore;
/* Logs connection events and some general router and scan stats */
private final WifiMetrics mWifiMetrics;
- /* Manages affiliated certificates for current user */
- private final WifiCertManager mCertManager;
private final WifiInjector mWifiInjector;
/* Backup/Restore Module */
@@ -206,6 +200,18 @@
private final ConcurrentHashMap<String, Integer> mIfaceIpModes;
/**
+ * One of: {@link WifiManager#WIFI_AP_STATE_DISABLED},
+ * {@link WifiManager#WIFI_AP_STATE_DISABLING},
+ * {@link WifiManager#WIFI_AP_STATE_ENABLED},
+ * {@link WifiManager#WIFI_AP_STATE_ENABLING},
+ * {@link WifiManager#WIFI_AP_STATE_FAILED}
+ *
+ * Access/maintenance MUST be done on the wifi service thread
+ */
+ private int mWifiApState = WifiManager.WIFI_AP_STATE_DISABLED;
+
+
+ /**
* Callback for use with LocalOnlyHotspot to unregister requesting applications upon death.
*
* @hide
@@ -438,7 +444,6 @@
mPowerManager = mContext.getSystemService(PowerManager.class);
mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
- mCertManager = mWifiInjector.getWifiCertManager();
mWifiLockManager = mWifiInjector.getWifiLockManager();
mWifiMulticastLockManager = mWifiInjector.getWifiMulticastLockManager();
HandlerThread wifiServiceHandlerThread = mWifiInjector.getWifiServiceHandlerThread();
@@ -795,8 +800,7 @@
}
// If SoftAp is enabled, only Settings is allowed to toggle wifi
- boolean apEnabled =
- mWifiStateMachine.syncGetWifiApState() != WifiManager.WIFI_AP_STATE_DISABLED;
+ boolean apEnabled = mWifiApState != WifiManager.WIFI_AP_STATE_DISABLED;
if (apEnabled && !isFromSettings) {
mLog.info("setWifiEnabled SoftAp not disabled: only Settings can enable wifi").flush();
@@ -857,32 +861,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},
@@ -894,7 +872,13 @@
public int getWifiApEnabledState() {
enforceAccessPermission();
mLog.info("getWifiApEnabledState uid=%").c(Binder.getCallingUid()).flush();
- return mWifiStateMachine.syncGetWifiApState();
+
+ // hand off work to our handler thread
+ MutableInt apState = new MutableInt(WifiManager.WIFI_AP_STATE_DISABLED);
+ mClientHandler.runWithScissors(() -> {
+ apState.value = mWifiApState;
+ }, 0);
+ return apState.value;
}
/**
@@ -1055,6 +1039,8 @@
/**
* Private method to handle SoftAp state changes
+ *
+ * <p> MUST be called from the WifiStateMachine thread.
*/
private void handleWifiApStateChange(
int currentState, int previousState, int errorCode, String ifaceName, int mode) {
@@ -1063,6 +1049,9 @@
+ " previousState=" + previousState + " errorCode= " + errorCode
+ " ifaceName=" + ifaceName + " mode=" + mode);
+ // update the tracking ap state variable
+ mWifiApState = currentState;
+
// check if we have a failure - since it is possible (worst case scenario where
// WifiController and WifiStateMachine are out of sync wrt modes) to get two FAILED
// notifications in a row, we need to handle this first.
@@ -1588,6 +1577,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
@@ -1744,12 +1753,19 @@
@Override
public WifiInfo getConnectionInfo(String callingPackage) {
enforceAccessPermission();
- mLog.info("getConnectionInfo uid=%").c(Binder.getCallingUid()).flush();
+ int uid = Binder.getCallingUid();
+ mLog.info("getConnectionInfo uid=%").c(uid).flush();
/*
* Make sure we have the latest information, by sending
* a status request to the supplicant.
*/
- return mWifiStateMachine.syncRequestConnectionInfo(callingPackage);
+ long ident = Binder.clearCallingIdentity();
+ try {
+ WifiInfo result = mWifiStateMachine.syncRequestConnectionInfo(callingPackage, uid);
+ return result;
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
/**
@@ -1888,16 +1904,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 +2394,7 @@
@Override
public void enableVerboseLogging(int verbose) {
enforceAccessPermission();
+ enforceNetworkSettingsPermission();
mLog.info("enableVerboseLogging uid=% verbose=%")
.c(Binder.getCallingUid())
.c(verbose).flush();
@@ -2395,9 +2407,7 @@
mWifiStateMachine.enableVerboseLogging(verbose);
mWifiLockManager.enableVerboseLogging(verbose);
mWifiMulticastLockManager.enableVerboseLogging(verbose);
- mWifiInjector.getWifiLastResortWatchdog().enableVerboseLogging(verbose);
- mWifiInjector.getWifiBackupRestore().enableVerboseLogging(verbose);
- LogcatLog.enableVerboseLogging(verbose);
+ mWifiInjector.enableVerboseLogging(verbose);
}
@Override
@@ -2425,38 +2435,6 @@
return mWifiStateMachine.getAggressiveHandover();
}
- @Override
- public void setAllowScansWithTraffic(int enabled) {
- enforceAccessPermission();
- mLog.info("setAllowScansWithTraffic uid=% enabled=%")
- .c(Binder.getCallingUid())
- .c(enabled).flush();
- mWifiStateMachine.setAllowScansWithTraffic(enabled);
- }
-
- @Override
- public int getAllowScansWithTraffic() {
- enforceAccessPermission();
- mLog.info("getAllowScansWithTraffic uid=%").c(Binder.getCallingUid()).flush();
- return mWifiStateMachine.getAllowScansWithTraffic();
- }
-
- @Override
- public boolean setEnableAutoJoinWhenAssociated(boolean enabled) {
- enforceChangePermission();
- mLog.info("setEnableAutoJoinWhenAssociated uid=% enabled=%")
- .c(Binder.getCallingUid())
- .c(enabled).flush();
- return mWifiStateMachine.setEnableAutoJoinWhenAssociated(enabled);
- }
-
- @Override
- public boolean getEnableAutoJoinWhenAssociated() {
- enforceAccessPermission();
- mLog.info("getEnableAutoJoinWhenAssociated uid=%").c(Binder.getCallingUid()).flush();
- return mWifiStateMachine.getEnableAutoJoinWhenAssociated();
- }
-
/* Return the Wifi Connection statistics object */
@Override
public WifiConnectionStatistics getConnectionStatistics() {
@@ -2564,14 +2542,6 @@
return sb.toString();
}
- public void hideCertFromUnaffiliatedUsers(String alias) {
- mCertManager.hideCertFromUnaffiliatedUsers(alias);
- }
-
- public String[] listClientCertsForCurrentUser() {
- return mCertManager.listClientCertsForCurrentUser();
- }
-
/**
* Enable/disable WifiConnectivityManager at runtime
*
@@ -2674,4 +2644,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..da4a6d4 100644
--- a/service/java/com/android/server/wifi/WifiStateMachine.java
+++ b/service/java/com/android/server/wifi/WifiStateMachine.java
@@ -29,9 +29,7 @@
import static android.telephony.TelephonyManager.CALL_STATE_IDLE;
import static android.telephony.TelephonyManager.CALL_STATE_OFFHOOK;
-import android.Manifest;
import android.app.ActivityManager;
-import android.app.AppGlobals;
import android.app.PendingIntent;
import android.bluetooth.BluetoothAdapter;
import android.content.BroadcastReceiver;
@@ -39,7 +37,6 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
-import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.database.ContentObserver;
import android.net.ConnectivityManager;
@@ -60,7 +57,6 @@
import android.net.TrafficStats;
import android.net.dhcp.DhcpClient;
import android.net.ip.IpClient;
-import android.net.wifi.IApInterface;
import android.net.wifi.IClientInterface;
import android.net.wifi.RssiPacketCountInfo;
import android.net.wifi.ScanResult;
@@ -71,18 +67,17 @@
import android.net.wifi.WifiConnectionStatistics;
import android.net.wifi.WifiEnterpriseConfig;
import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiLinkLayerStats;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiScanner;
import android.net.wifi.WifiSsid;
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;
import android.os.BatteryStats;
-import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
@@ -128,6 +123,7 @@
import com.android.server.wifi.util.TelephonyUtil.SimAuthRequestData;
import com.android.server.wifi.util.TelephonyUtil.SimAuthResponseData;
import com.android.server.wifi.util.WifiPermissionsUtil;
+import com.android.server.wifi.util.WifiPermissionsWrapper;
import java.io.BufferedReader;
import java.io.FileDescriptor;
@@ -181,9 +177,10 @@
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;
-
+ private final WifiPermissionsWrapper mWifiPermissionsWrapper;
/* debug flag, indicating if handling of ASSOCIATION_REJECT ended up blacklisting
* the corresponding BSSID.
*/
@@ -250,8 +247,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);
};
@@ -367,7 +365,7 @@
private DhcpResults mDhcpResults;
// NOTE: Do not return to clients - see syncRequestConnectionInfo()
- private final WifiInfo mWifiInfo;
+ private final ExtendedWifiInfo mWifiInfo;
private NetworkInfo mNetworkInfo;
private final NetworkCapabilities mDfltNetworkCapabilities;
private SupplicantStateTracker mSupplicantStateTracker;
@@ -698,8 +696,9 @@
/* Enable/Disable WifiConnectivityManager */
static final int CMD_ENABLE_WIFI_CONNECTIVITY_MANAGER = BASE + 166;
- /* 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 +724,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 +736,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 };
@@ -791,8 +793,6 @@
*/
private long mSupplicantScanIntervalMs;
- private boolean mEnableAutoJoinWhenAssociated;
- private int mAlwaysEnableScansWhileAssociated;
private final int mThresholdQualifiedRssi24;
private final int mThresholdQualifiedRssi5;
private final int mThresholdSaturatedRssi24;
@@ -943,8 +943,9 @@
mWifiMonitor = mWifiInjector.getWifiMonitor();
mWifiDiagnostics = mWifiInjector.makeWifiDiagnostics(mWifiNative);
+ mWifiPermissionsWrapper = mWifiInjector.getWifiPermissionsWrapper();
- mWifiInfo = new WifiInfo();
+ mWifiInfo = new ExtendedWifiInfo();
mSupplicantStateTracker =
mFacade.makeSupplicantStateTracker(context, mWifiConfigManager, getHandler());
@@ -1032,8 +1033,6 @@
com.android.internal.R.string.config_wifi_tcp_buffers);
// Load Device configs
- mEnableAutoJoinWhenAssociated = context.getResources().getBoolean(
- R.bool.config_wifi_framework_enable_associated_network_selection);
mThresholdQualifiedRssi24 = context.getResources().getInteger(
R.integer.config_wifi_framework_wifi_score_low_rssi_threshold_24GHz);
mThresholdQualifiedRssi5 = context.getResources().getInteger(
@@ -1243,6 +1242,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";
@@ -1271,26 +1271,6 @@
// mWifiConfigManager.trimANQPCache(true);
}
- public void setAllowScansWithTraffic(int enabled) {
- mAlwaysEnableScansWhileAssociated = enabled;
- }
-
- public int getAllowScansWithTraffic() {
- return mAlwaysEnableScansWhileAssociated;
- }
-
- /*
- * Dynamically turn on/off if switching networks while connected is allowd.
- */
- public boolean setEnableAutoJoinWhenAssociated(boolean enabled) {
- sendMessage(CMD_ENABLE_AUTOJOIN_WHEN_ASSOCIATED, enabled ? 1 : 0);
- return true;
- }
-
- public boolean getEnableAutoJoinWhenAssociated() {
- return mEnableAutoJoinWhenAssociated;
- }
-
private boolean setRandomMacOui() {
String oui = mContext.getResources().getString(R.string.config_wifi_random_mac_oui);
if (TextUtils.isEmpty(oui)) {
@@ -1337,7 +1317,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 +1443,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();
@@ -1696,9 +1675,9 @@
/**
* TODO: doc
*/
- public int syncGetWifiApState() {
- return mWifiApState.get();
- }
+ //public int syncGetWifiApState() {
+ // return mWifiApState.get();
+ //}
/**
* TODO: doc
@@ -1755,25 +1734,21 @@
/**
* Get status information for the current connection, if any.
*
+ * @param callingPackage string indicating the calling package of the caller
+ * @param uid the calling uid
* @return a {@link WifiInfo} object containing information about the current connection
*/
- public WifiInfo syncRequestConnectionInfo(String callingPackage) {
- int uid = Binder.getCallingUid();
+ public WifiInfo syncRequestConnectionInfo(String callingPackage, int uid) {
WifiInfo result = new WifiInfo(mWifiInfo);
- if (uid == Process.myUid()) return result;
boolean hideBssidAndSsid = true;
result.setMacAddress(WifiInfo.DEFAULT_MAC_ADDRESS);
- IPackageManager packageManager = AppGlobals.getPackageManager();
-
try {
- if (packageManager.checkUidPermission(Manifest.permission.LOCAL_MAC_ADDRESS,
- uid) == PackageManager.PERMISSION_GRANTED) {
+ if (mWifiPermissionsWrapper.getLocalMacAddressPermission(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 +1915,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 +1985,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
@@ -2241,16 +2244,8 @@
pw.println("mOperationalMode " + mOperationalMode);
pw.println("mUserWantsSuspendOpt " + mUserWantsSuspendOpt);
pw.println("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled);
- if (mCountryCode.getCountryCodeSentToDriver() != null) {
- pw.println("CountryCode sent to driver " + mCountryCode.getCountryCodeSentToDriver());
- } else {
- if (mCountryCode.getCountryCode() != null) {
- pw.println("CountryCode: " +
- mCountryCode.getCountryCode() + " was not sent to driver");
- } else {
- pw.println("CountryCode was not initialized");
- }
- }
+ mCountryCode.dump(fd, pw, args);
+
if (mNetworkFactory != null) {
mNetworkFactory.dump(fd, pw, args);
} else {
@@ -2277,6 +2272,7 @@
} else {
pw.println("mWifiConnectivityManager is not initialized");
}
+ mWifiInjector.getWakeupController().dump(fd, pw, args);
}
public void handleUserSwitch(int userId) {
@@ -2915,24 +2911,8 @@
// Update state
mWifiApState.set(wifiApState);
+ // TODO: when this code is removed, also remove syncGetWifiApStateByName()
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() {
@@ -3262,16 +3242,18 @@
|| stateChangeResult.wifiSsid.toString().isEmpty()) && isLinkDebouncing()) {
return state;
}
- // Network id is only valid when we start connecting
+ // Network id and SSID are only valid when we start connecting
if (SupplicantState.isConnecting(state)) {
mWifiInfo.setNetworkId(lookupFrameworkNetworkId(stateChangeResult.networkId));
+ mWifiInfo.setBSSID(stateChangeResult.BSSID);
+ mWifiInfo.setSSID(stateChangeResult.wifiSsid);
} else {
+ // Reset parameters according to WifiInfo.reset()
mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID);
+ mWifiInfo.setBSSID(null);
+ mWifiInfo.setSSID(null);
}
- mWifiInfo.setBSSID(stateChangeResult.BSSID);
- mWifiInfo.setSSID(stateChangeResult.wifiSsid);
-
final WifiConfiguration config = getCurrentWifiConfiguration();
if (config != null) {
mWifiInfo.setEphemeral(config.ephemeral);
@@ -3903,6 +3885,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 +4019,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 +4103,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 +4120,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 +4142,10 @@
// Tearing down the client interfaces below is going to stop our supplicant.
mWifiMonitor.stopAllMonitoring();
- mDeathRecipient.unlinkToDeath();
+ // stop hostapd in case it was running from SoftApMode
+ mWifiNative.stopSoftAp();
+
+ mWifiNative.deregisterWificondDeathHandler();
mWifiNative.tearDown();
}
@@ -4168,14 +4161,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;
@@ -4298,9 +4291,12 @@
transitionTo(mInitialState);
}
break;
+ case CMD_START_AP:
+ // now go directly to softap mode since we handle teardown in WSMP
+ transitionTo(mSoftApState);
+ break;
case CMD_START_SUPPLICANT:
case CMD_STOP_SUPPLICANT:
- case CMD_START_AP:
case CMD_STOP_AP:
case CMD_SET_OPERATIONAL_MODE:
messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
@@ -4450,10 +4446,12 @@
sendMessage(mBufferedScanMsg.remove());
break;
case CMD_START_AP:
- /* Cannot start soft AP while in client mode */
- loge("Failed to start soft AP with a running supplicant");
- setWifiApState(WIFI_AP_STATE_FAILED, WifiManager.SAP_START_FAILURE_GENERAL,
- null, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
+ // /* Cannot start soft AP while in client mode */
+ // loge("Failed to start soft AP with a running supplicant");
+ // setWifiApState(WIFI_AP_STATE_FAILED, WifiManager.SAP_START_FAILURE_GENERAL,
+ // null, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
+ // now go directly to softap mode since we handle teardown in WSMP
+ transitionTo(mSoftApState);
break;
case CMD_SET_OPERATIONAL_MODE:
mOperationalMode = message.arg1;
@@ -4532,15 +4530,6 @@
case CMD_ENABLE_WIFI_CONNECTIVITY_MANAGER:
mWifiConnectivityManager.enable(message.arg1 == 1 ? true : false);
break;
- case CMD_ENABLE_AUTOJOIN_WHEN_ASSOCIATED:
- final boolean allowed = (message.arg1 > 0);
- boolean old_state = mEnableAutoJoinWhenAssociated;
- mEnableAutoJoinWhenAssociated = allowed;
- if (!old_state && allowed && mScreenOn
- && getCurrentState() == mConnectedState) {
- mWifiConnectivityManager.forceConnectivityScan(WIFI_WORK_SOURCE);
- }
- break;
case CMD_SELECT_TX_POWER_SCENARIO:
int txPowerScenario = message.arg1;
logd("Setting Tx power scenario to " + txPowerScenario);
@@ -4660,7 +4649,14 @@
public void enter() {
mLastOperationMode = mOperationalMode;
mWifiStateTracker.updateState(WifiStateTracker.SCAN_MODE);
+ mWifiInjector.getWakeupController().start();
}
+
+ @Override
+ public void exit() {
+ mWifiInjector.getWakeupController().stop();
+ }
+
@Override
public boolean processMessage(Message message) {
logStateAndMessage(message, this);
@@ -4888,6 +4884,8 @@
// Let the system know that wifi is available in client mode.
setWifiState(WIFI_STATE_ENABLED);
+ mWifiInjector.getWakeupController().reset();
+
mNetworkInfo.setIsAvailable(true);
if (mNetworkAgent != null) mNetworkAgent.sendNetworkInfo(mNetworkInfo);
@@ -4918,6 +4916,7 @@
}
mWifiInfo.reset();
mWifiInfo.setSupplicantState(SupplicantState.DISCONNECTED);
+ setWifiState(WIFI_STATE_DISABLED);
}
@Override
@@ -5160,6 +5159,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 +5337,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 +5386,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 +5506,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;
}
@@ -5853,7 +5867,7 @@
break;
case CMD_DISCONNECT:
mWifiMetrics.logStaEvent(StaEvent.TYPE_FRAMEWORK_DISCONNECT,
- StaEvent.DISCONNECT_UNKNOWN);
+ StaEvent.DISCONNECT_GENERIC);
mWifiNative.disconnect();
transitionTo(mDisconnectingState);
break;
@@ -6697,7 +6711,7 @@
break;
case CMD_DISCONNECT:
mWifiMetrics.logStaEvent(StaEvent.TYPE_FRAMEWORK_DISCONNECT,
- StaEvent.DISCONNECT_UNKNOWN);
+ StaEvent.DISCONNECT_GENERIC);
mWifiNative.disconnect();
break;
/* Ignore network disconnect */
@@ -6798,8 +6812,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 +6825,7 @@
transitionTo(mDisconnectedState);
break;
case WifiMonitor.WPS_OVERLAP_EVENT:
+ mWifiMetrics.incrementWpsOverlapFailureCount();
replyToMessage(mSourceMessage, WifiManager.WPS_FAILED,
WifiManager.WPS_OVERLAP_ERROR);
mSourceMessage.recycle();
@@ -6818,6 +6835,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 +6847,7 @@
}
break;
case WifiMonitor.WPS_TIMEOUT_EVENT:
+ mWifiMetrics.incrementWpsTimeoutFailureCount();
replyToMessage(mSourceMessage, WifiManager.WPS_FAILED,
WifiManager.WPS_TIMED_OUT);
mSourceMessage.recycle();
@@ -6839,6 +6858,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 {
@@ -6935,6 +6955,7 @@
private String mIfaceName;
private int mMode;
+ /*
private class SoftApListener implements SoftApManager.Listener {
@Override
public void onStateChanged(int state, int reason) {
@@ -6947,6 +6968,7 @@
setWifiApState(state, reason, mIfaceName, mMode);
}
}
+ */
@Override
public void enter() {
@@ -6954,11 +6976,13 @@
if (message.what != CMD_START_AP) {
throw new RuntimeException("Illegal transition to SoftApState: " + message);
}
+ /*
SoftApModeConfiguration config = (SoftApModeConfiguration) message.obj;
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 +6991,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,18 +6999,21 @@
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());
+ config);
mSoftApManager.start();
mWifiStateTracker.updateState(WifiStateTracker.SOFT_AP);
+ */
}
@Override
@@ -7008,7 +7032,8 @@
/* Ignore start command when it is starting/started. */
break;
case CMD_STOP_AP:
- mSoftApManager.stop();
+ //mSoftApManager.stop();
+ transitionTo(mInitialState);
break;
case CMD_START_AP_FAILURE:
transitionTo(mInitialState);
diff --git a/service/java/com/android/server/wifi/WifiStateMachinePrime.java b/service/java/com/android/server/wifi/WifiStateMachinePrime.java
index 2006884..2d3aaba 100644
--- a/service/java/com/android/server/wifi/WifiStateMachinePrime.java
+++ b/service/java/com/android/server/wifi/WifiStateMachinePrime.java
@@ -16,14 +16,12 @@
package com.android.server.wifi;
-import android.net.wifi.IApInterface;
-import android.net.wifi.IWificond;
+import android.annotation.NonNull;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.os.INetworkManagementService;
import android.os.Looper;
import android.os.Message;
-import android.os.RemoteException;
import android.util.Log;
import com.android.internal.util.Protocol;
@@ -46,11 +44,12 @@
private final WifiInjector mWifiInjector;
private final Looper mLooper;
+ private final WifiNative mWifiNative;
private final INetworkManagementService mNMService;
- private IWificond mWificond;
+ private Queue<SoftApModeConfiguration> mApConfigQueue = new ConcurrentLinkedQueue<>();
- private Queue<WifiConfiguration> mApConfigQueue = new ConcurrentLinkedQueue<>();
+ private String mInterfaceName;
/* The base for wifi message types */
static final int BASE = Protocol.BASE_WIFI;
@@ -66,22 +65,17 @@
WifiStateMachinePrime(WifiInjector wifiInjector,
Looper looper,
+ WifiNative wifiNative,
INetworkManagementService nmService) {
mWifiInjector = wifiInjector;
mLooper = looper;
+ mWifiNative = wifiNative;
mNMService = nmService;
- // Clean up existing interfaces in wificond.
- // This ensures that the framework and wificond are in a consistent state after a framework
- // restart.
- try {
- mWificond = mWifiInjector.makeWificond();
- if (mWificond != null) {
- mWificond.tearDownInterfaces();
- }
- } catch (RemoteException e) {
- Log.e(TAG, "wificond died during framework startup");
- }
+ mInterfaceName = mWifiNative.getInterfaceName();
+
+ // make sure we do not have leftover state in the event of a restart
+ mWifiNative.tearDown();
}
/**
@@ -106,17 +100,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);
}
@@ -214,23 +204,14 @@
return HANDLED;
}
- private void tearDownInterfaces() {
- if (mWificond != null) {
- try {
- mWificond.tearDownInterfaces();
- } catch (RemoteException e) {
- // There is very little we can do here
- Log.e(TAG, "Failed to tear down interfaces via wificond");
- }
- mWificond = null;
- }
- return;
+ private void cleanup() {
+ mWifiNative.disableSupplicant();
+ mWifiNative.tearDown();
}
class ClientModeState extends State {
@Override
public void enter() {
- mWificond = mWifiInjector.makeWificond();
}
@Override
@@ -243,7 +224,7 @@
@Override
public void exit() {
- tearDownInterfaces();
+ cleanup();
}
}
@@ -269,36 +250,18 @@
}
class SoftAPModeState extends State {
- IApInterface mApInterface = null;
@Override
public void enter() {
+ // For now - need to clean up from other mode management in WSM
+ cleanup();
+
final Message message = mModeStateMachine.getCurrentMessage();
if (message.what != ModeStateMachine.CMD_START_SOFT_AP_MODE) {
Log.d(TAG, "Entering SoftAPMode (idle)");
return;
}
- // 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);
- return;
- }
mModeStateMachine.transitionTo(mSoftAPModeActiveState);
}
@@ -316,7 +279,8 @@
// not in active state, nothing to stop.
break;
case CMD_START_AP_FAILURE:
- Log.e(TAG, "Failed to start SoftApMode. Wait for next mode command.");
+ // with interface management in softapmanager, no setup failures can be seen
+ // here
break;
case CMD_AP_STOPPED:
Log.d(TAG, "SoftApModeActiveState stopped. Wait for next mode command.");
@@ -329,27 +293,23 @@
@Override
public void exit() {
- tearDownInterfaces();
+ // while in transition, cleanup is done on entering states. in the future, each
+ // mode will clean up their own state on exit
+ //cleanup();
}
- protected IApInterface getInterface() {
- 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);
- }
+ private void initializationFailed(String message) {
+ Log.e(TAG, message);
+ mModeStateMachine.sendMessage(CMD_START_AP_FAILURE);
}
}
class WifiDisabledState extends State {
@Override
public void enter() {
- // make sure everything is torn down
Log.d(TAG, "Entering WifiDisabledState");
+ // make sure everything is torn down
+ cleanup();
}
@Override
@@ -409,17 +369,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);
- mActiveModeManager.start();
+ new SoftApListener(), softApModeConfig);
+ this.mActiveModeManager.start();
}
@Override
diff --git a/service/java/com/android/server/wifi/WifiVendorHal.java b/service/java/com/android/server/wifi/WifiVendorHal.java
index 12674aa..d6b568d 100644
--- a/service/java/com/android/server/wifi/WifiVendorHal.java
+++ b/service/java/com/android/server/wifi/WifiVendorHal.java
@@ -59,7 +59,6 @@
import android.net.wifi.RttManager.ResponderConfig;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiLinkLayerStats;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiScanner;
import android.net.wifi.WifiSsid;
@@ -67,16 +66,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 +143,7 @@
}
/**
- * Logs if the argument is false.
+ * Logs the argument along with the method name.
*
* Always returns its argument.
*/
@@ -158,6 +163,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 +225,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 +273,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 +295,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 +313,219 @@
* @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);
+ }
+ }
+
+ private class StaInterfaceDestroyedListenerInternal implements InterfaceDestroyedListener {
+ private final InterfaceDestroyedListener mExternalListener;
+
+ StaInterfaceDestroyedListenerInternal(InterfaceDestroyedListener externalListener) {
+ mExternalListener = externalListener;
+ }
+
+ @Override
+ public void onDestroyed(@NonNull String ifaceName) {
+ synchronized (sLock) {
+ mIWifiStaIfaces.remove(ifaceName);
+ }
+ if (mExternalListener != null) {
+ mExternalListener.onDestroyed(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 = mHalDeviceManager.createStaIface(
+ new StaInterfaceDestroyedListenerInternal(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);
+ }
+ }
+
+ private class ApInterfaceDestroyedListenerInternal implements InterfaceDestroyedListener {
+ private final InterfaceDestroyedListener mExternalListener;
+
+ ApInterfaceDestroyedListenerInternal(InterfaceDestroyedListener externalListener) {
+ mExternalListener = externalListener;
+ }
+
+ @Override
+ public void onDestroyed(@NonNull String ifaceName) {
+ synchronized (sLock) {
+ mIWifiApIfaces.remove(ifaceName);
+ }
+ if (mExternalListener != null) {
+ mExternalListener.onDestroyed(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 = mHalDeviceManager.createApIface(
+ new ApInterfaceDestroyedListenerInternal(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 +557,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 +586,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 +753,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 +788,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 +809,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 +831,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 +855,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 +872,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;
});
@@ -715,7 +904,6 @@
static WifiLinkLayerStats frameworkFromHalLinkLayerStats(StaLinkLayerStats stats) {
if (stats == null) return null;
WifiLinkLayerStats out = new WifiLinkLayerStats();
- // unpopulated: out.status, out.SSID, out.BSSID
out.beacon_rx = stats.iface.beaconRx;
out.rssi_mgmt = stats.iface.avgRssiMgmt;
// Statistics are broken out by Wireless Multimedia Extensions categories
@@ -751,7 +939,7 @@
out.rx_time = radioStats.rxTimeInMs;
out.on_time_scan = radioStats.onTimeInMsForScan;
}
- // unused: stats.timeStampInMs;
+ out.timeStampInMs = stats.timeStampInMs;
return out;
}
@@ -762,12 +950,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 +1066,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 +1083,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 +1624,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 +1646,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 +1680,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 +1692,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 +1707,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 +1722,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 +2010,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 +2101,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 +2143,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 +2183,7 @@
/**
* Start sending the specified keep alive packets periodically.
*
+ * @param ifaceName Name of the interface.
* @param slot
* @param srcMac
* @param keepAlivePacket
@@ -2054,16 +2191,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 +2221,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 +2256,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 +2287,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 +2373,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 +2398,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 +2427,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 +2449,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 +2462,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 +2500,7 @@
}
}
- WifiStatus status = mIWifiStaIface.configureRoaming(roamingConfig);
+ WifiStatus status = iface.configureRoaming(roamingConfig);
if (!ok(status)) return false;
} catch (RemoteException e) {
handleRemoteException(e);
@@ -2582,8 +2736,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..d951257 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;
@@ -44,8 +43,8 @@
*/
public class WifiAwareClientState {
private static final String TAG = "WifiAwareClientState";
- private static final boolean DBG = false;
private static final boolean VDBG = false; // STOPSHIP if true
+ /* package */ boolean mDbg = false;
/* package */ static final int CLUSTER_CHANGE_EVENT_STARTED = 0;
/* package */ static final int CLUSTER_CHANGE_EVENT_JOINED = 1;
@@ -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..b263597 100644
--- a/service/java/com/android/server/wifi/aware/WifiAwareDataPathStateManager.java
+++ b/service/java/com/android/server/wifi/aware/WifiAwareDataPathStateManager.java
@@ -76,9 +76,8 @@
*/
public class WifiAwareDataPathStateManager {
private static final String TAG = "WifiAwareDataPathStMgr";
-
- private static final boolean DBG = false;
private static final boolean VDBG = false; // STOPSHIP if true
+ /* package */ boolean mDbg = false;
private static final String AWARE_INTERFACE_PREFIX = "aware_data";
private static final String NETWORK_TAG = "WIFI_AWARE_FACTORY";
@@ -122,6 +121,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());
@@ -203,6 +203,7 @@
String name = AWARE_INTERFACE_PREFIX + i;
mMgr.deleteDataPathInterface(name);
}
+ mMgr.releaseAwareInterface();
}
/**
@@ -349,8 +350,8 @@
if (nnri == null) {
Log.w(TAG, "onDataPathRequest: can't find a request with specified pubSubId=" + pubSubId
+ ", mac=" + String.valueOf(HexEncoding.encode(mac)));
- if (DBG) {
- Log.d(TAG, "onDataPathRequest: network request cache = " + mNetworkRequestsCache);
+ if (VDBG) {
+ Log.v(TAG, "onDataPathRequest: network request cache = " + mNetworkRequestsCache);
}
mMgr.respondToDataPathRequest(false, ndpId, "", null, null, false);
return null;
@@ -407,8 +408,8 @@
if (nnri == null) {
Log.w(TAG, "onRespondToDataPathRequest: can't find a request with specified ndpId="
+ ndpId);
- if (DBG) {
- Log.d(TAG, "onRespondToDataPathRequest: network request cache = "
+ if (VDBG) {
+ Log.v(TAG, "onRespondToDataPathRequest: network request cache = "
+ mNetworkRequestsCache);
}
return;
@@ -530,8 +531,8 @@
nnri.startTimestamp = SystemClock.elapsedRealtime(); // update time-stamp for duration
mAwareMetrics.recordNdpCreation(nnri.uid, mNetworkRequestsCache);
} else {
- if (DBG) {
- Log.d(TAG, "onDataPathConfirm: data-path for networkSpecifier=" + networkSpecifier
+ if (VDBG) {
+ Log.v(TAG, "onDataPathConfirm: data-path for networkSpecifier=" + networkSpecifier
+ " rejected - reason=" + reason);
}
mNetworkRequestsCache.remove(networkSpecifier);
@@ -554,8 +555,8 @@
Map.Entry<WifiAwareNetworkSpecifier, AwareNetworkRequestInformation> nnriE =
getNetworkRequestByNdpId(ndpId);
if (nnriE == null) {
- if (DBG) {
- Log.d(TAG, "onDataPathEnd: network request not found for ndpId=" + ndpId);
+ if (VDBG) {
+ Log.v(TAG, "onDataPathEnd: network request not found for ndpId=" + ndpId);
}
return;
}
@@ -589,12 +590,12 @@
* - i.e. when we're proceeding with data-path setup).
*/
public void handleDataPathTimeout(NetworkSpecifier networkSpecifier) {
- if (VDBG) Log.v(TAG, "handleDataPathTimeout: networkSpecifier=" + networkSpecifier);
+ if (mDbg) Log.v(TAG, "handleDataPathTimeout: networkSpecifier=" + networkSpecifier);
AwareNetworkRequestInformation nnri = mNetworkRequestsCache.remove(networkSpecifier);
if (nnri == null) {
- if (DBG) {
- Log.d(TAG,
+ if (mDbg) {
+ Log.v(TAG,
"handleDataPathTimeout: network request not found for networkSpecifier="
+ networkSpecifier);
}
@@ -659,8 +660,8 @@
// look up specifier - are we being called again?
AwareNetworkRequestInformation nnri = mNetworkRequestsCache.get(networkSpecifier);
if (nnri != null) {
- if (DBG) {
- Log.d(TAG, "WifiAwareNetworkFactory.acceptRequest: request=" + request
+ if (VDBG) {
+ Log.v(TAG, "WifiAwareNetworkFactory.acceptRequest: request=" + request
+ " - already in cache with state=" + nnri.state);
}
@@ -727,8 +728,8 @@
}
if (nnri.state != AwareNetworkRequestInformation.STATE_IDLE) {
- if (DBG) {
- Log.d(TAG, "WifiAwareNetworkFactory.needNetworkFor: networkRequest="
+ if (VDBG) {
+ Log.v(TAG, "WifiAwareNetworkFactory.needNetworkFor: networkRequest="
+ networkRequest + " - already in progress");
// TODO: understand how/when can be called again/while in progress (seems
// to be related to score re-calculation after a network agent is created)
diff --git a/service/java/com/android/server/wifi/aware/WifiAwareDiscoverySessionState.java b/service/java/com/android/server/wifi/aware/WifiAwareDiscoverySessionState.java
index 86f4e37..062b5d9 100644
--- a/service/java/com/android/server/wifi/aware/WifiAwareDiscoverySessionState.java
+++ b/service/java/com/android/server/wifi/aware/WifiAwareDiscoverySessionState.java
@@ -38,8 +38,8 @@
*/
public class WifiAwareDiscoverySessionState {
private static final String TAG = "WifiAwareDiscSessState";
- private static final boolean DBG = false;
private static final boolean VDBG = false; // STOPSHIP if true
+ /* package */ boolean mDbg = false;
private int mNextPeerIdToBeAllocated = 100; // used to create a unique peer ID
@@ -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);
}
@@ -289,8 +296,8 @@
PeerInfo newPeerInfo = new PeerInfo(requestorInstanceId, peerMac);
mPeerInfoByRequestorInstanceId.put(newPeerId, newPeerInfo);
- if (DBG) {
- Log.d(TAG, "New peer info: peerId=" + newPeerId + ", peerInfo=" + newPeerInfo);
+ if (VDBG) {
+ Log.v(TAG, "New peer info: peerId=" + newPeerId + ", peerInfo=" + newPeerInfo);
}
return newPeerId;
diff --git a/service/java/com/android/server/wifi/aware/WifiAwareMetrics.java b/service/java/com/android/server/wifi/aware/WifiAwareMetrics.java
index c45c6dc..4f5f46b 100644
--- a/service/java/com/android/server/wifi/aware/WifiAwareMetrics.java
+++ b/service/java/com/android/server/wifi/aware/WifiAwareMetrics.java
@@ -40,7 +40,8 @@
*/
public class WifiAwareMetrics {
private static final String TAG = "WifiAwareMetrics";
- private static final boolean DBG = false;
+ private static final boolean VDBG = false;
+ /* package */ boolean mDbg = false;
// Histogram: 8 buckets (i=0, ..., 7) of 9 slots in range 10^i -> 10^(i+1)
// Buckets:
diff --git a/service/java/com/android/server/wifi/aware/WifiAwareNativeApi.java b/service/java/com/android/server/wifi/aware/WifiAwareNativeApi.java
index a6e724f..66bbff5 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;
@@ -55,8 +56,8 @@
*/
public class WifiAwareNativeApi implements WifiAwareShellCommand.DelegatedShellCommand {
private static final String TAG = "WifiAwareNativeApi";
- private static final boolean DBG = false;
private static final boolean VDBG = false; // STOPSHIP if true
+ /* package */ boolean mDbg = false;
private static final String SERVICE_NAME_FOR_OOB_DATA_PATH = "Wi-Fi Aware Data Path";
@@ -170,7 +171,7 @@
* match with the original request.
*/
public boolean getCapabilities(short transactionId) {
- if (VDBG) Log.v(TAG, "getCapabilities: transactionId=" + transactionId);
+ if (mDbg) Log.v(TAG, "getCapabilities: transactionId=" + transactionId);
IWifiNanIface iface = mHal.getWifiNanIface();
if (iface == null) {
@@ -207,7 +208,7 @@
public boolean enableAndConfigure(short transactionId, ConfigRequest configRequest,
boolean notifyIdentityChange, boolean initialConfiguration, boolean isInteractive,
boolean isIdle) {
- if (VDBG) {
+ if (mDbg) {
Log.v(TAG, "enableAndConfigure: transactionId=" + transactionId + ", configRequest="
+ configRequest + ", notifyIdentityChange=" + notifyIdentityChange
+ ", initialConfiguration=" + initialConfiguration
@@ -369,7 +370,7 @@
* used in the async callback to match with the original request.
*/
public boolean disable(short transactionId) {
- if (VDBG) Log.d(TAG, "disable");
+ if (mDbg) Log.d(TAG, "disable");
IWifiNanIface iface = mHal.getWifiNanIface();
if (iface == null) {
@@ -401,7 +402,7 @@
* @param publishConfig Configuration of the discovery session.
*/
public boolean publish(short transactionId, byte publishId, PublishConfig publishConfig) {
- if (VDBG) {
+ if (mDbg) {
Log.d(TAG, "publish: transactionId=" + transactionId + ", publishId=" + publishId
+ ", config=" + publishConfig);
}
@@ -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;
@@ -463,7 +466,7 @@
*/
public boolean subscribe(short transactionId, byte subscribeId,
SubscribeConfig subscribeConfig) {
- if (VDBG) {
+ if (mDbg) {
Log.d(TAG, "subscribe: transactionId=" + transactionId + ", subscribeId=" + subscribeId
+ ", config=" + subscribeConfig);
}
@@ -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;
@@ -529,7 +546,7 @@
*/
public boolean sendMessage(short transactionId, byte pubSubId, int requestorInstanceId,
byte[] dest, byte[] message, int messageId) {
- if (VDBG) {
+ if (mDbg) {
Log.d(TAG,
"sendMessage: transactionId=" + transactionId + ", pubSubId=" + pubSubId
+ ", requestorInstanceId=" + requestorInstanceId + ", dest="
@@ -577,7 +594,7 @@
* creating a session.
*/
public boolean stopPublish(short transactionId, byte pubSubId) {
- if (VDBG) {
+ if (mDbg) {
Log.d(TAG, "stopPublish: transactionId=" + transactionId + ", pubSubId=" + pubSubId);
}
@@ -610,7 +627,7 @@
* creating a session.
*/
public boolean stopSubscribe(short transactionId, byte pubSubId) {
- if (VDBG) {
+ if (mDbg) {
Log.d(TAG, "stopSubscribe: transactionId=" + transactionId + ", pubSubId=" + pubSubId);
}
@@ -643,7 +660,7 @@
* @param interfaceName The name of the interface, e.g. "aware0".
*/
public boolean createAwareNetworkInterface(short transactionId, String interfaceName) {
- if (VDBG) {
+ if (mDbg) {
Log.v(TAG, "createAwareNetworkInterface: transactionId=" + transactionId + ", "
+ "interfaceName=" + interfaceName);
}
@@ -676,7 +693,7 @@
* @param interfaceName The name of the interface, e.g. "aware0".
*/
public boolean deleteAwareNetworkInterface(short transactionId, String interfaceName) {
- if (VDBG) {
+ if (mDbg) {
Log.v(TAG, "deleteAwareNetworkInterface: transactionId=" + transactionId + ", "
+ "interfaceName=" + interfaceName);
}
@@ -722,7 +739,7 @@
public boolean initiateDataPath(short transactionId, int peerId, int channelRequestType,
int channel, byte[] peer, String interfaceName, byte[] pmk, String passphrase,
boolean isOutOfBand, Capabilities capabilities) {
- if (VDBG) {
+ if (mDbg) {
Log.v(TAG, "initiateDataPath: transactionId=" + transactionId + ", peerId=" + peerId
+ ", channelRequestType=" + channelRequestType + ", channel=" + channel
+ ", peer=" + String.valueOf(HexEncoding.encode(peer)) + ", interfaceName="
@@ -799,7 +816,7 @@
public boolean respondToDataPathRequest(short transactionId, boolean accept, int ndpId,
String interfaceName, byte[] pmk, String passphrase, boolean isOutOfBand,
Capabilities capabilities) {
- if (VDBG) {
+ if (mDbg) {
Log.v(TAG, "respondToDataPathRequest: transactionId=" + transactionId + ", accept="
+ accept + ", int ndpId=" + ndpId + ", interfaceName=" + interfaceName);
}
@@ -861,7 +878,7 @@
* @param ndpId The NDP (Aware data path) ID to be terminated.
*/
public boolean endDataPath(short transactionId, int ndpId) {
- if (VDBG) {
+ if (mDbg) {
Log.v(TAG, "endDataPath: transactionId=" + transactionId + ", ndpId=" + ndpId);
}
diff --git a/service/java/com/android/server/wifi/aware/WifiAwareNativeCallback.java b/service/java/com/android/server/wifi/aware/WifiAwareNativeCallback.java
index 2121160..78f8a28 100644
--- a/service/java/com/android/server/wifi/aware/WifiAwareNativeCallback.java
+++ b/service/java/com/android/server/wifi/aware/WifiAwareNativeCallback.java
@@ -46,8 +46,8 @@
public class WifiAwareNativeCallback extends IWifiNanIfaceEventCallback.Stub implements
WifiAwareShellCommand.DelegatedShellCommand {
private static final String TAG = "WifiAwareNativeCallback";
- private static final boolean DBG = false;
private static final boolean VDBG = false;
+ /* package */ boolean mDbg = false;
private final WifiAwareStateManager mWifiAwareStateManager;
@@ -141,7 +141,7 @@
@Override
public void notifyCapabilitiesResponse(short id, WifiNanStatus status,
NanCapabilities capabilities) {
- if (VDBG) {
+ if (mDbg) {
Log.v(TAG, "notifyCapabilitiesResponse: id=" + id + ", status=" + statusString(status)
+ ", capabilities=" + capabilities);
}
@@ -176,7 +176,7 @@
@Override
public void notifyEnableResponse(short id, WifiNanStatus status) {
- if (VDBG) Log.v(TAG, "notifyEnableResponse: id=" + id + ", status=" + statusString(status));
+ if (mDbg) Log.v(TAG, "notifyEnableResponse: id=" + id + ", status=" + statusString(status));
if (status.status == NanStatusType.ALREADY_ENABLED) {
Log.wtf(TAG, "notifyEnableResponse: id=" + id + ", already enabled!?");
@@ -192,7 +192,7 @@
@Override
public void notifyConfigResponse(short id, WifiNanStatus status) {
- if (VDBG) Log.v(TAG, "notifyConfigResponse: id=" + id + ", status=" + statusString(status));
+ if (mDbg) Log.v(TAG, "notifyConfigResponse: id=" + id + ", status=" + statusString(status));
if (status.status == NanStatusType.SUCCESS) {
mWifiAwareStateManager.onConfigSuccessResponse(id);
@@ -203,7 +203,7 @@
@Override
public void notifyDisableResponse(short id, WifiNanStatus status) {
- if (VDBG) {
+ if (mDbg) {
Log.v(TAG, "notifyDisableResponse: id=" + id + ", status=" + statusString(status));
}
@@ -216,7 +216,7 @@
@Override
public void notifyStartPublishResponse(short id, WifiNanStatus status, byte publishId) {
- if (VDBG) {
+ if (mDbg) {
Log.v(TAG, "notifyStartPublishResponse: id=" + id + ", status=" + statusString(status)
+ ", publishId=" + publishId);
}
@@ -230,7 +230,7 @@
@Override
public void notifyStopPublishResponse(short id, WifiNanStatus status) {
- if (VDBG) {
+ if (mDbg) {
Log.v(TAG, "notifyStopPublishResponse: id=" + id + ", status=" + statusString(status));
}
@@ -244,7 +244,7 @@
@Override
public void notifyStartSubscribeResponse(short id, WifiNanStatus status, byte subscribeId) {
- if (VDBG) {
+ if (mDbg) {
Log.v(TAG, "notifyStartSubscribeResponse: id=" + id + ", status=" + statusString(status)
+ ", subscribeId=" + subscribeId);
}
@@ -258,7 +258,7 @@
@Override
public void notifyStopSubscribeResponse(short id, WifiNanStatus status) {
- if (VDBG) {
+ if (mDbg) {
Log.v(TAG, "notifyStopSubscribeResponse: id=" + id + ", status="
+ statusString(status));
}
@@ -273,7 +273,7 @@
@Override
public void notifyTransmitFollowupResponse(short id, WifiNanStatus status) {
- if (VDBG) {
+ if (mDbg) {
Log.v(TAG, "notifyTransmitFollowupResponse: id=" + id + ", status="
+ statusString(status));
}
@@ -287,7 +287,7 @@
@Override
public void notifyCreateDataInterfaceResponse(short id, WifiNanStatus status) {
- if (VDBG) {
+ if (mDbg) {
Log.v(TAG, "notifyCreateDataInterfaceResponse: id=" + id + ", status="
+ statusString(status));
}
@@ -298,7 +298,7 @@
@Override
public void notifyDeleteDataInterfaceResponse(short id, WifiNanStatus status) {
- if (VDBG) {
+ if (mDbg) {
Log.v(TAG, "notifyDeleteDataInterfaceResponse: id=" + id + ", status="
+ statusString(status));
}
@@ -310,7 +310,7 @@
@Override
public void notifyInitiateDataPathResponse(short id, WifiNanStatus status,
int ndpInstanceId) {
- if (VDBG) {
+ if (mDbg) {
Log.v(TAG, "notifyInitiateDataPathResponse: id=" + id + ", status="
+ statusString(status) + ", ndpInstanceId=" + ndpInstanceId);
}
@@ -324,7 +324,7 @@
@Override
public void notifyRespondToDataPathIndicationResponse(short id, WifiNanStatus status) {
- if (VDBG) {
+ if (mDbg) {
Log.v(TAG, "notifyRespondToDataPathIndicationResponse: id=" + id
+ ", status=" + statusString(status));
}
@@ -335,7 +335,7 @@
@Override
public void notifyTerminateDataPathResponse(short id, WifiNanStatus status) {
- if (VDBG) {
+ if (mDbg) {
Log.v(TAG, "notifyTerminateDataPathResponse: id=" + id + ", status="
+ statusString(status));
}
@@ -346,7 +346,7 @@
@Override
public void eventClusterEvent(NanClusterEventInd event) {
- if (VDBG) {
+ if (mDbg) {
Log.v(TAG, "eventClusterEvent: eventType=" + event.eventType + ", addr="
+ String.valueOf(HexEncoding.encode(event.addr)));
}
@@ -367,7 +367,7 @@
@Override
public void eventDisabled(WifiNanStatus status) {
- if (VDBG) Log.v(TAG, "eventDisabled: status=" + statusString(status));
+ if (mDbg) Log.v(TAG, "eventDisabled: status=" + statusString(status));
incrementCbCount(CB_EV_DISABLED);
mWifiAwareStateManager.onAwareDownNotification(status.status);
@@ -375,7 +375,7 @@
@Override
public void eventPublishTerminated(byte sessionId, WifiNanStatus status) {
- if (VDBG) {
+ if (mDbg) {
Log.v(TAG, "eventPublishTerminated: sessionId=" + sessionId + ", status="
+ statusString(status));
}
@@ -386,7 +386,7 @@
@Override
public void eventSubscribeTerminated(byte sessionId, WifiNanStatus status) {
- if (VDBG) {
+ if (mDbg) {
Log.v(TAG, "eventSubscribeTerminated: sessionId=" + sessionId + ", status="
+ statusString(status));
}
@@ -397,7 +397,7 @@
@Override
public void eventMatch(NanMatchInd event) {
- if (VDBG) {
+ if (mDbg) {
Log.v(TAG, "eventMatch: discoverySessionId=" + event.discoverySessionId + ", peerId="
+ event.peerId + ", addr=" + String.valueOf(HexEncoding.encode(event.addr))
+ ", serviceSpecificInfo=" + Arrays.toString(
@@ -405,18 +405,22 @@
+ (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
public void eventMatchExpired(byte discoverySessionId, int peerId) {
- if (VDBG) {
+ if (mDbg) {
Log.v(TAG, "eventMatchExpired: discoverySessionId=" + discoverySessionId
+ ", peerId=" + peerId);
}
@@ -427,7 +431,7 @@
@Override
public void eventFollowupReceived(NanFollowupReceivedInd event) {
- if (VDBG) {
+ if (mDbg) {
Log.v(TAG, "eventFollowupReceived: discoverySessionId=" + event.discoverySessionId
+ ", peerId=" + event.peerId + ", addr=" + String.valueOf(
HexEncoding.encode(event.addr)) + ", serviceSpecificInfo=" + Arrays.toString(
@@ -442,7 +446,7 @@
@Override
public void eventTransmitFollowup(short id, WifiNanStatus status) {
- if (VDBG) {
+ if (mDbg) {
Log.v(TAG, "eventTransmitFollowup: id=" + id + ", status=" + statusString(status));
}
incrementCbCount(CB_EV_TRANSMIT_FOLLOWUP);
@@ -456,7 +460,7 @@
@Override
public void eventDataPathRequest(NanDataPathRequestInd event) {
- if (VDBG) {
+ if (mDbg) {
Log.v(TAG, "eventDataPathRequest: discoverySessionId=" + event.discoverySessionId
+ ", peerDiscMacAddr=" + String.valueOf(
HexEncoding.encode(event.peerDiscMacAddr)) + ", ndpInstanceId="
@@ -470,7 +474,7 @@
@Override
public void eventDataPathConfirm(NanDataPathConfirmInd event) {
- if (VDBG) {
+ if (mDbg) {
Log.v(TAG, "onDataPathConfirm: ndpInstanceId=" + event.ndpInstanceId
+ ", peerNdiMacAddr=" + String.valueOf(HexEncoding.encode(event.peerNdiMacAddr))
+ ", dataPathSetupSuccess=" + event.dataPathSetupSuccess + ", reason="
@@ -485,7 +489,7 @@
@Override
public void eventDataPathTerminated(int ndpInstanceId) {
- if (VDBG) Log.v(TAG, "eventDataPathTerminated: ndpInstanceId=" + ndpInstanceId);
+ if (mDbg) Log.v(TAG, "eventDataPathTerminated: ndpInstanceId=" + ndpInstanceId);
incrementCbCount(CB_EV_DATA_PATH_TERMINATED);
mWifiAwareStateManager.onDataPathEndNotification(ndpInstanceId);
diff --git a/service/java/com/android/server/wifi/aware/WifiAwareNativeManager.java b/service/java/com/android/server/wifi/aware/WifiAwareNativeManager.java
index e855d81..b9dd680 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;
@@ -34,19 +36,21 @@
*/
public class WifiAwareNativeManager {
private static final String TAG = "WifiAwareNativeManager";
- private static final boolean DBG = false;
+ private static final boolean VDBG = false;
+ /* package */ boolean mDbg = false;
// to be used for synchronizing access to any of the WifiAwareNative objects
private final Object mLock = new Object();
private WifiAwareStateManager mWifiAwareStateManager;
private HalDeviceManager mHalDeviceManager;
+ private Handler mHandler;
private WifiAwareNativeCallback mWifiAwareNativeCallback;
private IWifiNanIface mWifiNanIface = null;
- private InterfaceDestroyedListener mInterfaceDestroyedListener =
- new InterfaceDestroyedListener();
+ private InterfaceDestroyedListener mInterfaceDestroyedListener;
private InterfaceAvailableForRequestListener mInterfaceAvailableForRequestListener =
new InterfaceAvailableForRequestListener();
+ private int mReferenceCount = 0;
WifiAwareNativeManager(WifiAwareStateManager awareStateManager,
HalDeviceManager halDeviceManager,
@@ -56,29 +60,34 @@
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() {
@Override
public void onStatusChanged() {
- if (DBG) Log.d(TAG, "onStatusChanged");
+ if (VDBG) Log.v(TAG, "onStatusChanged");
// only care about isStarted (Wi-Fi started) not isReady - since if not
// ready then Wi-Fi will also be down.
if (mHalDeviceManager.isStarted()) {
// 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();
}
}
- }, null);
+ }, mHandler);
if (mHalDeviceManager.isStarted()) {
mHalDeviceManager.registerInterfaceAvailableForRequestListener(
- IfaceType.NAN, mInterfaceAvailableForRequestListener, null);
- tryToGetAware();
+ IfaceType.NAN, mInterfaceAvailableForRequestListener, mHandler);
}
}
@@ -94,21 +103,33 @@
}
/**
- * Attempt to obtain the HAL NAN interface. If available then enables Aware usage.
+ * Attempt to obtain the HAL NAN interface.
*/
- private void tryToGetAware() {
+ public void tryToGetAware() {
synchronized (mLock) {
- if (DBG) Log.d(TAG, "tryToGetAware: mWifiNanIface=" + mWifiNanIface);
+ if (mDbg) {
+ Log.d(TAG, "tryToGetAware: mWifiNanIface=" + mWifiNanIface + ", mReferenceCount="
+ + mReferenceCount);
+ }
if (mWifiNanIface != null) {
+ mReferenceCount++;
return;
}
+ if (mHalDeviceManager == null) {
+ Log.e(TAG, "tryToGetAware: mHalDeviceManager is null!?");
+ awareIsDown();
+ return;
+ }
+
+ mInterfaceDestroyedListener = new InterfaceDestroyedListener();
IWifiNanIface iface = mHalDeviceManager.createNanIface(mInterfaceDestroyedListener,
- null);
+ mHandler);
if (iface == null) {
- if (DBG) Log.d(TAG, "Was not able to obtain an IWifiNanIface");
+ Log.e(TAG, "Was not able to obtain an IWifiNanIface (even though enabled!?)");
+ awareIsDown();
} else {
- if (DBG) Log.d(TAG, "Obtained an IWifiNanIface");
+ if (mDbg) Log.v(TAG, "Obtained an IWifiNanIface");
try {
WifiStatus status = iface.registerEventCallback(mWifiAwareNativeCallback);
@@ -116,44 +137,92 @@
Log.e(TAG, "IWifiNanIface.registerEventCallback error: " + statusString(
status));
mHalDeviceManager.removeIface(iface);
+ awareIsDown();
return;
}
} catch (RemoteException e) {
Log.e(TAG, "IWifiNanIface.registerEventCallback exception: " + e);
- mHalDeviceManager.removeIface(iface);
+ awareIsDown();
return;
}
mWifiNanIface = iface;
- mWifiAwareStateManager.enableUsage();
+ mReferenceCount = 1;
}
}
}
+ /**
+ * Release the HAL NAN interface.
+ */
+ public void releaseAware() {
+ if (mDbg) {
+ Log.d(TAG, "releaseAware: mWifiNanIface=" + mWifiNanIface + ", mReferenceCount="
+ + mReferenceCount);
+ }
+
+ if (mWifiNanIface == null) {
+ return;
+ }
+ if (mHalDeviceManager == null) {
+ Log.e(TAG, "releaseAware: mHalDeviceManager is null!?");
+ return;
+ }
+
+ synchronized (mLock) {
+ mReferenceCount--;
+ if (mReferenceCount != 0) {
+ return;
+ }
+ mInterfaceDestroyedListener.active = false;
+ mInterfaceDestroyedListener = null;
+ mHalDeviceManager.removeIface(mWifiNanIface);
+ mWifiNanIface = null;
+ }
+ }
+
private void awareIsDown() {
synchronized (mLock) {
- if (DBG) Log.d(TAG, "awareIsDown: mWifiNanIface=" + mWifiNanIface);
- if (mWifiNanIface != null) {
- mWifiNanIface = null;
- mWifiAwareStateManager.disableUsage();
+ if (mDbg) {
+ Log.d(TAG, "awareIsDown: mWifiNanIface=" + mWifiNanIface + ", mReferenceCount ="
+ + mReferenceCount);
}
+ mWifiNanIface = null;
+ mReferenceCount = 0;
+ mWifiAwareStateManager.disableUsage();
}
}
private class InterfaceDestroyedListener implements
HalDeviceManager.InterfaceDestroyedListener {
+ public boolean active = true;
+
@Override
- public void onDestroyed() {
- if (DBG) Log.d(TAG, "Interface was destroyed");
- awareIsDown();
+ public void onDestroyed(@NonNull String ifaceName) {
+ if (mDbg) {
+ Log.d(TAG, "Interface was destroyed: mWifiNanIface=" + mWifiNanIface + ", active="
+ + active);
+ }
+ if (active && mWifiNanIface != null) {
+ awareIsDown();
+ } // else: we released it locally so no need to disable usage
}
}
private class InterfaceAvailableForRequestListener implements
HalDeviceManager.InterfaceAvailableForRequestListener {
@Override
- public void onAvailableForRequest() {
- if (DBG) Log.d(TAG, "Interface is possibly available");
- tryToGetAware();
+ public void onAvailabilityChanged(boolean isAvailable) {
+ if (mDbg) {
+ Log.d(TAG, "Interface availability = " + isAvailable + ", mWifiNanIface="
+ + mWifiNanIface);
+ }
+ synchronized (mLock) {
+ if (isAvailable) {
+ mWifiAwareStateManager.enableUsage();
+ } else if (mWifiNanIface == null) { // not available could mean already have NAN
+ mWifiAwareStateManager.disableUsage();
+ }
+ }
}
}
@@ -172,6 +241,7 @@
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("WifiAwareNativeManager:");
pw.println(" mWifiNanIface: " + mWifiNanIface);
+ pw.println(" mReferenceCount: " + mReferenceCount);
mWifiAwareNativeCallback.dump(fd, pw, args);
mHalDeviceManager.dump(fd, pw, args);
}
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/WifiAwareService.java b/service/java/com/android/server/wifi/aware/WifiAwareService.java
index e210d3e..f38c373 100644
--- a/service/java/com/android/server/wifi/aware/WifiAwareService.java
+++ b/service/java/com/android/server/wifi/aware/WifiAwareService.java
@@ -69,7 +69,9 @@
HandlerThread awareHandlerThread = wifiInjector.getWifiAwareHandlerThread();
mImpl.start(awareHandlerThread, wifiAwareStateManager, wifiAwareShellCommand,
wifiInjector.getWifiMetrics().getWifiAwareMetrics(),
- wifiInjector.getWifiPermissionsWrapper());
+ wifiInjector.getWifiPermissionsUtil(),
+ wifiInjector.getWifiPermissionsWrapper(), wifiInjector.getFrameworkFacade(),
+ wifiAwareNativeManager, wifiAwareNativeApi, wifiAwareNativeCallback);
} else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
mImpl.startLate();
}
diff --git a/service/java/com/android/server/wifi/aware/WifiAwareServiceImpl.java b/service/java/com/android/server/wifi/aware/WifiAwareServiceImpl.java
index dd4c2e0..f92249e 100644
--- a/service/java/com/android/server/wifi/aware/WifiAwareServiceImpl.java
+++ b/service/java/com/android/server/wifi/aware/WifiAwareServiceImpl.java
@@ -16,33 +16,40 @@
package com.android.server.wifi.aware;
+import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.database.ContentObserver;
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;
import android.os.Binder;
+import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ShellCallback;
+import android.provider.Settings;
import android.util.Log;
import android.util.SparseArray;
import android.util.SparseIntArray;
+import com.android.server.wifi.FrameworkFacade;
+import com.android.server.wifi.WifiInjector;
+import com.android.server.wifi.util.WifiPermissionsUtil;
import com.android.server.wifi.util.WifiPermissionsWrapper;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.util.Arrays;
+import java.util.List;
/**
* Implementation of the IWifiAwareManager AIDL interface. Performs validity
@@ -52,10 +59,11 @@
*/
public class WifiAwareServiceImpl extends IWifiAwareManager.Stub {
private static final String TAG = "WifiAwareService";
- private static final boolean DBG = false;
private static final boolean VDBG = false; // STOPSHIP if true
+ /* package */ boolean mDbg = false;
private Context mContext;
+ private WifiPermissionsUtil mWifiPermissionsUtil;
private WifiAwareStateManager mStateManager;
private WifiAwareShellCommand mShellCommand;
@@ -63,7 +71,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) {
@@ -84,12 +91,56 @@
*/
public void start(HandlerThread handlerThread, WifiAwareStateManager awareStateManager,
WifiAwareShellCommand awareShellCommand, WifiAwareMetrics awareMetrics,
- WifiPermissionsWrapper permissionsWrapper) {
+ WifiPermissionsUtil wifiPermissionsUtil, WifiPermissionsWrapper permissionsWrapper,
+ FrameworkFacade frameworkFacade, WifiAwareNativeManager wifiAwareNativeManager,
+ WifiAwareNativeApi wifiAwareNativeApi,
+ WifiAwareNativeCallback wifiAwareNativeCallback) {
Log.i(TAG, "Starting Wi-Fi Aware service");
+ mWifiPermissionsUtil = wifiPermissionsUtil;
mStateManager = awareStateManager;
mShellCommand = awareShellCommand;
mStateManager.start(mContext, handlerThread.getLooper(), awareMetrics, permissionsWrapper);
+
+ frameworkFacade.registerContentObserver(mContext,
+ Settings.Global.getUriFor(Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED), true,
+ new ContentObserver(new Handler(handlerThread.getLooper())) {
+ @Override
+ public void onChange(boolean selfChange) {
+ enableVerboseLogging(frameworkFacade.getIntegerSetting(mContext,
+ Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, 0), awareStateManager,
+ wifiAwareNativeManager, wifiAwareNativeApi,
+ wifiAwareNativeCallback);
+ }
+ });
+ enableVerboseLogging(frameworkFacade.getIntegerSetting(mContext,
+ Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, 0), awareStateManager,
+ wifiAwareNativeManager, wifiAwareNativeApi, wifiAwareNativeCallback);
+ }
+
+ private void enableVerboseLogging(int verbose, WifiAwareStateManager awareStateManager,
+ WifiAwareNativeManager wifiAwareNativeManager, WifiAwareNativeApi wifiAwareNativeApi,
+ WifiAwareNativeCallback wifiAwareNativeCallback) {
+ boolean dbg;
+
+ if (verbose > 0) {
+ dbg = true;
+ } else {
+ dbg = false;
+ }
+ if (VDBG) {
+ dbg = true; // just override
+ }
+
+ mDbg = dbg;
+ awareStateManager.mDbg = dbg;
+ if (awareStateManager.mDataPathMgr != null) { // needed for unit tests
+ awareStateManager.mDataPathMgr.mDbg = dbg;
+ WifiInjector.getInstance().getWifiMetrics().getWifiAwareMetrics().mDbg = dbg;
+ }
+ wifiAwareNativeCallback.mDbg = dbg;
+ wifiAwareNativeManager.mDbg = dbg;
+ wifiAwareNativeApi.mDbg = dbg;
}
/**
@@ -130,11 +181,11 @@
}
if (notifyOnIdentityChanged) {
- enforceLocationPermission();
+ enforceLocationPermission(callingPackage, getMockableCallingUid());
}
if (configRequest != null) {
- enforceConnectivityInternalPermission();
+ enforceNetworkStackPermission();
} else {
configRequest = new ConfigRequest.Builder().build();
}
@@ -148,7 +199,7 @@
clientId = mNextClientId++;
}
- if (VDBG) {
+ if (mDbg) {
Log.v(TAG, "connect: uid=" + uid + ", clientId=" + clientId + ", configRequest"
+ configRequest + ", notifyOnIdentityChanged=" + notifyOnIdentityChanged);
}
@@ -156,7 +207,7 @@
IBinder.DeathRecipient dr = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
- if (DBG) Log.d(TAG, "binderDied: clientId=" + clientId);
+ if (mDbg) Log.v(TAG, "binderDied: clientId=" + clientId);
binder.unlinkToDeath(this, 0);
synchronized (mLock) {
@@ -196,7 +247,7 @@
int uid = getMockableCallingUid();
enforceClientValidity(uid, clientId);
- if (VDBG) Log.v(TAG, "disconnect: uid=" + uid + ", clientId=" + clientId);
+ if (mDbg) Log.v(TAG, "disconnect: uid=" + uid + ", clientId=" + clientId);
if (binder == null) {
throw new IllegalArgumentException("Binder must not be null");
@@ -230,11 +281,11 @@
}
@Override
- public void publish(int clientId, PublishConfig publishConfig,
+ public void publish(String callingPackage, int clientId, PublishConfig publishConfig,
IWifiAwareDiscoverySessionCallback callback) {
enforceAccessPermission();
enforceChangePermission();
- enforceLocationPermission();
+ enforceLocationPermission(callingPackage, getMockableCallingUid());
if (callback == null) {
throw new IllegalArgumentException("Callback must not be null");
@@ -242,7 +293,8 @@
if (publishConfig == null) {
throw new IllegalArgumentException("PublishConfig must not be null");
}
- publishConfig.assertValid(mStateManager.getCharacteristics());
+ publishConfig.assertValid(mStateManager.getCharacteristics(),
+ mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_RTT));
int uid = getMockableCallingUid();
enforceClientValidity(uid, clientId);
@@ -262,7 +314,8 @@
if (publishConfig == null) {
throw new IllegalArgumentException("PublishConfig must not be null");
}
- publishConfig.assertValid(mStateManager.getCharacteristics());
+ publishConfig.assertValid(mStateManager.getCharacteristics(),
+ mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_RTT));
int uid = getMockableCallingUid();
enforceClientValidity(uid, clientId);
@@ -275,11 +328,11 @@
}
@Override
- public void subscribe(int clientId, SubscribeConfig subscribeConfig,
+ public void subscribe(String callingPackage, int clientId, SubscribeConfig subscribeConfig,
IWifiAwareDiscoverySessionCallback callback) {
enforceAccessPermission();
enforceChangePermission();
- enforceLocationPermission();
+ enforceLocationPermission(callingPackage, getMockableCallingUid());
if (callback == null) {
throw new IllegalArgumentException("Callback must not be null");
@@ -287,7 +340,8 @@
if (subscribeConfig == null) {
throw new IllegalArgumentException("SubscribeConfig must not be null");
}
- subscribeConfig.assertValid(mStateManager.getCharacteristics());
+ subscribeConfig.assertValid(mStateManager.getCharacteristics(),
+ mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_RTT));
int uid = getMockableCallingUid();
enforceClientValidity(uid, clientId);
@@ -307,7 +361,8 @@
if (subscribeConfig == null) {
throw new IllegalArgumentException("SubscribeConfig must not be null");
}
- subscribeConfig.assertValid(mStateManager.getCharacteristics());
+ subscribeConfig.assertValid(mStateManager.getCharacteristics(),
+ mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_RTT));
int uid = getMockableCallingUid();
enforceClientValidity(uid, clientId);
@@ -326,7 +381,7 @@
enforceChangePermission();
if (retryCount != 0) {
- enforceConnectivityInternalPermission();
+ enforceNetworkStackPermission();
}
if (message != null && message.length
@@ -352,30 +407,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
@@ -419,13 +454,11 @@
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE, TAG);
}
- private void enforceLocationPermission() {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
- TAG);
+ private void enforceLocationPermission(String callingPackage, int uid) {
+ mWifiPermissionsUtil.enforceLocationPermission(callingPackage, uid);
}
- 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..5ae6902 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;
/**
@@ -69,8 +69,8 @@
*/
public class WifiAwareStateManager implements WifiAwareShellCommand.DelegatedShellCommand {
private static final String TAG = "WifiAwareStateManager";
- private static final boolean DBG = false;
private static final boolean VDBG = false; // STOPSHIP if true
+ /* package */ boolean mDbg = false;
@VisibleForTesting
public static final String HAL_COMMAND_TIMEOUT_TAG = TAG + " HAL Command Timeout";
@@ -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;
@@ -120,6 +119,8 @@
private static final int COMMAND_TYPE_TRANSMIT_NEXT_MESSAGE = 119;
private static final int COMMAND_TYPE_RECONFIGURE = 120;
private static final int COMMAND_TYPE_DELAYED_INITIALIZATION = 121;
+ private static final int COMMAND_TYPE_GET_AWARE = 122;
+ private static final int COMMAND_TYPE_RELEASE_AWARE = 123;
private static final int RESPONSE_TYPE_ON_CONFIG_SUCCESS = 200;
private static final int RESPONSE_TYPE_ON_CONFIG_FAIL = 201;
@@ -167,7 +168,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 +185,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 +205,6 @@
private volatile Capabilities mCapabilities;
private volatile Characteristics mCharacteristics = null;
private WifiAwareStateMachine mSm;
- private WifiAwareRttStateManager mRtt;
public WifiAwareDataPathStateManager mDataPathMgr;
private PowerManager mPowerManager;
@@ -345,10 +346,9 @@
mContext = context;
mAwareMetrics = awareMetrics;
mSm = new WifiAwareStateMachine(TAG, looper);
- mSm.setDbg(DBG);
+ mSm.setDbg(VDBG);
mSm.start();
- mRtt = new WifiAwareRttStateManager();
mDataPathMgr = new WifiAwareDataPathStateManager(this);
mDataPathMgr.start(mContext, mSm.getHandler().getLooper(), awareMetrics,
permissionsWrapper);
@@ -417,6 +417,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
*/
@@ -430,6 +472,26 @@
}
/**
+ * Place a request to get the Wi-Fi Aware interface (before which no HAL command can be
+ * executed).
+ */
+ public void getAwareInterface() {
+ Message msg = mSm.obtainMessage(MESSAGE_TYPE_COMMAND);
+ msg.arg1 = COMMAND_TYPE_GET_AWARE;
+ mSm.sendMessage(msg);
+ }
+
+ /**
+ * Place a request to release the Wi-Fi Aware interface (after which no HAL command can be
+ * executed).
+ */
+ public void releaseAwareInterface() {
+ Message msg = mSm.obtainMessage(MESSAGE_TYPE_COMMAND);
+ msg.arg1 = COMMAND_TYPE_RELEASE_AWARE;
+ mSm.sendMessage(msg);
+ }
+
+ /**
* Place a request for a new client connection on the state machine queue.
*/
public void connect(int clientId, int uid, int pid, String callingPackage,
@@ -553,20 +615,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 +968,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 +976,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);
}
@@ -1093,7 +1143,7 @@
WifiAwareNetworkSpecifier networkSpecifier =
(WifiAwareNetworkSpecifier) msg.obj;
- if (VDBG) {
+ if (mDbg) {
Log.v(TAG, "MESSAGE_TYPE_DATA_PATH_TIMEOUT: networkSpecifier="
+ networkSpecifier);
}
@@ -1231,9 +1281,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: {
@@ -1308,8 +1360,8 @@
int retryCount = sentMessage.getData()
.getInt(MESSAGE_BUNDLE_KEY_RETRY_COUNT);
if (retryCount > 0 && reason == NanStatusType.NO_OTA_ACK) {
- if (DBG) {
- Log.d(TAG,
+ if (VDBG) {
+ Log.v(TAG,
"NOTIFICATION_TYPE_ON_MESSAGE_SEND_FAIL: transactionId="
+ transactionId + ", reason=" + reason
+ ": retransmitting - retryCount=" + retryCount);
@@ -1525,18 +1577,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 +1653,15 @@
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;
+ case COMMAND_TYPE_GET_AWARE:
+ mWifiAwareNativeManager.tryToGetAware();
+ waitForResponse = false;
+ break;
+ case COMMAND_TYPE_RELEASE_AWARE:
+ mWifiAwareNativeManager.releaseAware();
waitForResponse = false;
break;
default:
@@ -1758,7 +1805,7 @@
}
private void processTimeout(Message msg) {
- if (VDBG) {
+ if (mDbg) {
Log.v(TAG, "processTimeout: msg=" + msg);
}
@@ -1827,9 +1874,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"
@@ -1870,6 +1914,14 @@
"processTimeout: COMMAND_TYPE_DELAYED_INITIALIZATION - shouldn't be "
+ "waiting!");
break;
+ case COMMAND_TYPE_GET_AWARE:
+ Log.wtf(TAG,
+ "processTimeout: COMMAND_TYPE_GET_AWARE - shouldn't be waiting!");
+ break;
+ case COMMAND_TYPE_RELEASE_AWARE:
+ Log.wtf(TAG,
+ "processTimeout: COMMAND_TYPE_RELEASE_AWARE - shouldn't be waiting!");
+ break;
default:
Log.wtf(TAG, "processTimeout: this isn't a COMMAND -- msg=" + msg);
/* fall-through */
@@ -1902,7 +1954,7 @@
}
private void processSendMessageTimeout() {
- if (VDBG) {
+ if (mDbg) {
Log.v(TAG, "processSendMessageTimeout: mHostQueuedSendMessages.size()="
+ mHostQueuedSendMessages.size() + ", mFwQueuedSendMessages.size()="
+ mFwQueuedSendMessages.size() + ", mSendQueueBlocked="
@@ -1924,7 +1976,7 @@
long messageEnqueueTime = message.getData().getLong(
MESSAGE_BUNDLE_KEY_SEND_MESSAGE_ENQUEUE_TIME);
if (first || messageEnqueueTime + AWARE_SEND_MESSAGE_TIMEOUT <= currentTime) {
- if (VDBG) {
+ if (mDbg) {
Log.v(TAG, "processSendMessageTimeout: expiring - transactionId="
+ transactionId + ", message=" + message
+ ", due to messageEnqueueTime=" + messageEnqueueTime
@@ -2037,6 +2089,7 @@
WifiAwareClientState client = new WifiAwareClientState(mContext, clientId, uid, pid,
callingPackage, callback, configRequest, notifyIdentityChange,
SystemClock.elapsedRealtime());
+ client.mDbg = mDbg;
client.onInterfaceAddressChange(mCurrentDiscoveryInterfaceMac);
mClients.append(clientId, client);
mAwareMetrics.recordAttachSession(uid, notifyIdentityChange, mClients);
@@ -2045,6 +2098,10 @@
boolean notificationRequired =
doesAnyClientNeedIdentityChangeNotifications() || notifyIdentityChange;
+ if (mCurrentAwareConfiguration == null) {
+ mWifiAwareNativeManager.tryToGetAware();
+ }
+
boolean success = mWifiAwareNativeApi.enableAndConfigure(transactionId, merged,
notificationRequired, mCurrentAwareConfiguration == null,
mPowerManager.isInteractive(), mPowerManager.isDeviceIdleMode());
@@ -2275,12 +2332,16 @@
private void enableUsageLocal() {
if (VDBG) Log.v(TAG, "enableUsageLocal: mUsageEnabled=" + mUsageEnabled);
+ if (mCapabilities == null) {
+ getAwareInterface();
+ queryCapabilities();
+ releaseAwareInterface();
+ }
+
if (mUsageEnabled) {
return;
}
-
mUsageEnabled = true;
- queryCapabilities();
sendAwareStateChangedBroadcast(true);
mAwareMetrics.recordEnableUsage();
@@ -2308,49 +2369,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,
@@ -2428,6 +2446,7 @@
WifiAwareClientState client = new WifiAwareClientState(mContext, clientId, uid, pid,
callingPackage, callback, configRequest, notifyIdentityChange,
SystemClock.elapsedRealtime());
+ client.mDbg = mDbg;
mClients.put(clientId, client);
mAwareMetrics.recordAttachSession(uid, notifyIdentityChange, mClients);
try {
@@ -2543,6 +2562,7 @@
WifiAwareDiscoverySessionState session = new WifiAwareDiscoverySessionState(
mWifiAwareNativeApi, sessionId, pubSubId, callback, isPublish,
SystemClock.elapsedRealtime());
+ session.mDbg = mDbg;
client.addSession(session);
mAwareMetrics.recordDiscoverySession(client.getUid(),
@@ -2718,8 +2738,8 @@
}
if (success) {
- if (DBG) {
- Log.d(TAG, "onCreateDataPathInterfaceResponseLocal: successfully created interface "
+ if (VDBG) {
+ Log.v(TAG, "onCreateDataPathInterfaceResponseLocal: successfully created interface "
+ command.obj);
}
mDataPathMgr.onInterfaceCreated((String) command.obj);
@@ -2739,8 +2759,8 @@
}
if (success) {
- if (DBG) {
- Log.d(TAG, "onDeleteDataPathInterfaceResponseLocal: successfully deleted interface "
+ if (VDBG) {
+ Log.v(TAG, "onDeleteDataPathInterfaceResponseLocal: successfully deleted interface "
+ command.obj);
}
mDataPathMgr.onInterfaceDeleted((String) command.obj);
@@ -2823,13 +2843,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 +2860,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) {
@@ -2887,7 +2909,10 @@
private void onAwareDownLocal() {
if (VDBG) {
- Log.v(TAG, "onAwareDown");
+ Log.v(TAG, "onAwareDown: mCurrentAwareConfiguration=" + mCurrentAwareConfiguration);
+ }
+ if (mCurrentAwareConfiguration == null) {
+ return;
}
for (int i = 0; i < mClients.size(); ++i) {
@@ -3061,7 +3086,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..12305d4
--- /dev/null
+++ b/service/java/com/android/server/wifi/hotspot2/OsuNetworkConnection.java
@@ -0,0 +1,256 @@
+/*
+ * 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.ConnectivityManager;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
+import android.net.wifi.WifiConfiguration;
+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 static final int TIMEOUT_MS = 10000;
+
+ private final Context mContext;
+
+ private boolean mVerboseLoggingEnabled = false;
+ private WifiManager mWifiManager;
+ private ConnectivityManager mConnectivityManager;
+ private ConnectivityCallbacks mConnectivityCallbacks;
+ private Callbacks mCallbacks;
+ private Handler mHandler;
+ private Network mNetwork = null;
+ 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.WIFI_STATE_CHANGED_ACTION);
+ BroadcastReceiver receiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
+ int state = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
+ WifiManager.WIFI_STATE_UNKNOWN);
+ 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();
+ }
+ }
+ }
+ };
+ mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
+ mContext.registerReceiver(receiver, filter, null, handler);
+ mWifiEnabled = mWifiManager.isWifiEnabled();
+ mConnectivityManager =
+ (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+ mConnectivityCallbacks = new ConnectivityCallbacks();
+ mHandler = handler;
+ }
+
+ /**
+ * 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;
+ mNetwork = null;
+ mConnected = false;
+ }
+
+ /**
+ * 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 (!mWifiEnabled) {
+ 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;
+ }
+ NetworkRequest networkRequest = null;
+ networkRequest = new NetworkRequest.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_WIFI).build();
+ mConnectivityManager.requestNetwork(networkRequest, mConnectivityCallbacks, mHandler,
+ TIMEOUT_MS);
+ 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);
+ }
+ 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;
+ }
+
+ private class ConnectivityCallbacks extends ConnectivityManager.NetworkCallback {
+ @Override
+ public void onLinkPropertiesChanged(Network network, LinkProperties linkProperties) {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "onLinkPropertiesChanged for network=" + network
+ + " isProvisioned?" + linkProperties.isProvisioned());
+ }
+ if (linkProperties.isProvisioned() && mNetwork == null) {
+ mNetwork = network;
+ mConnected = true;
+ if (mCallbacks != null) {
+ mCallbacks.onConnected(network);
+ }
+ }
+ }
+
+ @Override
+ public void onUnavailable() {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "onUnvailable ");
+ }
+ if (mCallbacks != null) {
+ mCallbacks.onTimeOut();
+ }
+ }
+
+ @Override
+ public void onLost(Network network) {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "onLost " + network);
+ }
+ if (network != mNetwork) {
+ Log.w(TAG, "Irrelevant network lost notification");
+ return;
+ }
+ if (mCallbacks != null) {
+ mCallbacks.onDisconnected();
+ }
+ }
+ }
+}
+
diff --git a/service/java/com/android/server/wifi/hotspot2/OsuServerConnection.java b/service/java/com/android/server/wifi/hotspot2/OsuServerConnection.java
new file mode 100644
index 0000000..469100c
--- /dev/null
+++ b/service/java/com/android/server/wifi/hotspot2/OsuServerConnection.java
@@ -0,0 +1,191 @@
+/*
+ * 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.net.Network;
+import android.util.Log;
+
+import java.io.IOException;
+import java.net.URL;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+
+/**
+ * Provides methods to interface with the OSU server
+ */
+public class OsuServerConnection {
+ private static final String TAG = "OsuServerConnection";
+
+ private static final String HTTP = "http";
+ private static final String HTTPS = "https";
+
+ private SSLSocketFactory mSocketFactory;
+ private URL mUrl;
+ private Network mNetwork;
+ private WFATrustManager mTrustManager;
+ private HttpsURLConnection mUrlConnection = null;
+ private PasspointProvisioner.OsuServerCallbacks mOsuServerCallbacks;
+ private boolean mSetupComplete = false;
+ private boolean mVerboseLoggingEnabled = false;
+
+ /**
+ * Sets up callback for event
+ * @param callbacks OsuServerCallbacks to be invoked for server related events
+ */
+ public void setEventCallback(PasspointProvisioner.OsuServerCallbacks callbacks) {
+ mOsuServerCallbacks = callbacks;
+ }
+
+ /**
+ * Initialize socket factory for server connection using HTTPS
+ * @param tlsVersion String indicating the TLS version that will be used
+ */
+ public void init(String tlsVersion) {
+ // TODO(sohanirao) : Create and pass in a custom WFA Keystore
+ try {
+ // TODO(sohanirao) : Use the custom key store instead
+ mTrustManager = new WFATrustManager(KeyStore.getInstance("AndroidCAStore"));
+ SSLContext tlsContext = SSLContext.getInstance(tlsVersion);
+ tlsContext.init(null, new TrustManager[] { mTrustManager }, null);
+ mSocketFactory = tlsContext.getSocketFactory();
+ } catch (KeyStoreException | NoSuchAlgorithmException | KeyManagementException e) {
+ Log.w(TAG, "Initialization failed");
+ e.printStackTrace();
+ return;
+ }
+ mSetupComplete = true;
+ }
+
+ /**
+ * Provides the capability to run OSU server validation
+ * @return boolean true if capability available
+ */
+ public boolean canValidateServer() {
+ return mSetupComplete;
+ }
+
+ /**
+ * Enables verbose logging
+ * @param verbose a value greater than zero enables verbose logging
+ */
+ public void enableVerboseLogging(int verbose) {
+ mVerboseLoggingEnabled = verbose > 0 ? true : false;
+ }
+
+ /**
+ * Connect to the OSU server
+ * @param url Osu Server's URL
+ * @param network current network connection
+ * @return boolean value, true if connection was successful
+ *
+ * Relies on the caller to ensure that the capability to validate the OSU
+ * Server is available.
+ */
+ public boolean connect(URL url, Network network) {
+ mNetwork = network;
+ mUrl = url;
+ HttpsURLConnection urlConnection = null;
+ try {
+ urlConnection = (HttpsURLConnection) mNetwork.openConnection(mUrl);
+ urlConnection.setSSLSocketFactory(mSocketFactory);
+ urlConnection.connect();
+ } catch (IOException e) {
+ Log.e(TAG, "Unable to establish a URL connection");
+ e.printStackTrace();
+ return false;
+ }
+ mUrlConnection = urlConnection;
+ return true;
+ }
+
+ /**
+ * Validate the OSU server
+ */
+ public boolean validateProvider(String friendlyName) {
+ X509Certificate[] certs = mTrustManager.getTrustChain();
+ if (certs == null) {
+ return false;
+ }
+ // TODO(sohanirao) : Validate friendly name
+ return true;
+ }
+
+ /**
+ * Clean up
+ */
+ public void cleanup() {
+ mUrlConnection.disconnect();
+ }
+
+ private class WFATrustManager implements X509TrustManager {
+ private X509Certificate[] mTrustChain;
+ KeyStore mKeyStore;
+
+ WFATrustManager(KeyStore ks) {
+ mKeyStore = ks;
+ }
+
+ @Override
+ public void checkClientTrusted(X509Certificate[] chain, String authType)
+ throws CertificateException {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "checkClientTrusted " + authType);
+ }
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] chain, String authType)
+ throws CertificateException {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "checkServerTrusted " + authType);
+ }
+ boolean certsValid = false;
+ for (X509Certificate cert : chain) {
+ // TODO(sohanirao) : Validation of certs
+ certsValid = true;
+ }
+ mTrustChain = chain;
+ if (mOsuServerCallbacks != null) {
+ mOsuServerCallbacks.onServerValidationStatus(
+ mOsuServerCallbacks.getSessionId(), certsValid);
+ }
+ }
+
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "getAcceptedIssuers ");
+ }
+ return null;
+ }
+
+ public X509Certificate[] getTrustChain() {
+ return mTrustChain;
+ }
+ }
+}
+
diff --git a/service/java/com/android/server/wifi/hotspot2/PasspointConfigStoreData.java b/service/java/com/android/server/wifi/hotspot2/PasspointConfigStoreData.java
index 38401d2..553a38b 100644
--- a/service/java/com/android/server/wifi/hotspot2/PasspointConfigStoreData.java
+++ b/service/java/com/android/server/wifi/hotspot2/PasspointConfigStoreData.java
@@ -307,6 +307,7 @@
String clientCertificateAlias = null;
String clientPrivateKeyAlias = null;
boolean hasEverConnected = false;
+ boolean shared = false;
PasspointConfiguration config = null;
while (XmlUtils.nextElementWithin(in, outerTagDepth)) {
if (in.getAttributeValue(null, "name") != null) {
@@ -351,7 +352,7 @@
}
return new PasspointProvider(config, mKeyStore, mSimAccessor, providerId, creatorUid,
caCertificateAlias, clientCertificateAlias, clientPrivateKeyAlias,
- hasEverConnected);
+ hasEverConnected, shared);
}
/**
diff --git a/service/java/com/android/server/wifi/hotspot2/PasspointManager.java b/service/java/com/android/server/wifi/hotspot2/PasspointManager.java
index 5d79ba4..329306a 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,28 @@
mProviderIndex = 0;
wifiConfigStore.registerStoreData(objectFactory.makePasspointConfigStoreData(
mKeyStore, mSimAccessor, new DataSourceHandler()));
+ mPasspointProvisioner = objectFactory.makePasspointProvisioner(context,
+ objectFactory.makeOsuNetworkConnection(context),
+ objectFactory.makeOsuServerConnection());
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 +346,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 +397,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 +408,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 +556,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.
*
@@ -630,8 +721,20 @@
mSimAccessor, mProviderIndex++, wifiConfig.creatorUid,
enterpriseConfig.getCaCertificateAlias(),
enterpriseConfig.getClientCertificateAlias(),
- enterpriseConfig.getClientCertificateAlias(), false);
+ enterpriseConfig.getClientCertificateAlias(), false, false);
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..6cf3a7e 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,36 @@
public CertificateVerifier makeCertificateVerifier() {
return new CertificateVerifier();
}
+
+ /**
+ * Create an instance of {@link PasspointProvisioner}.
+ *
+ * @param context
+ * @return {@link PasspointProvisioner}
+ */
+ public PasspointProvisioner makePasspointProvisioner(Context context,
+ OsuNetworkConnection osuNetworkConnection,
+ OsuServerConnection osuServerConnection) {
+ return new PasspointProvisioner(context, osuNetworkConnection,
+ osuServerConnection);
+ }
+
+ /**
+ * Create an instance of {@link OsuNetworkConnection}.
+ *
+ * @param context
+ * @return {@link OsuNetworkConnection}
+ */
+ public OsuNetworkConnection makeOsuNetworkConnection(Context context) {
+ return new OsuNetworkConnection(context);
+ }
+
+ /**
+ * Create an instance of {@link OsuServerConnection}.
+ *
+ * @return {@link OsuServerConnection}
+ */
+ public OsuServerConnection makeOsuServerConnection() {
+ return new OsuServerConnection();
+ }
}
diff --git a/service/java/com/android/server/wifi/hotspot2/PasspointProvider.java b/service/java/com/android/server/wifi/hotspot2/PasspointProvider.java
index c7943ed..23ab57f 100644
--- a/service/java/com/android/server/wifi/hotspot2/PasspointProvider.java
+++ b/service/java/com/android/server/wifi/hotspot2/PasspointProvider.java
@@ -88,16 +88,17 @@
private final AuthParam mAuthParam;
private boolean mHasEverConnected;
+ private boolean mIsShared;
public PasspointProvider(PasspointConfiguration config, WifiKeyStore keyStore,
SIMAccessor simAccessor, long providerId, int creatorUid) {
- this(config, keyStore, simAccessor, providerId, creatorUid, null, null, null, false);
+ this(config, keyStore, simAccessor, providerId, creatorUid, null, null, null, false, false);
}
public PasspointProvider(PasspointConfiguration config, WifiKeyStore keyStore,
SIMAccessor simAccessor, long providerId, int creatorUid, String caCertificateAlias,
String clientCertificateAlias, String clientPrivateKeyAlias,
- boolean hasEverConnected) {
+ boolean hasEverConnected, boolean isShared) {
// Maintain a copy of the configuration to avoid it being updated by others.
mConfig = new PasspointConfiguration(config);
mKeyStore = keyStore;
@@ -107,6 +108,7 @@
mClientCertificateAlias = clientCertificateAlias;
mClientPrivateKeyAlias = clientPrivateKeyAlias;
mHasEverConnected = hasEverConnected;
+ mIsShared = isShared;
// Setup EAP method and authentication parameter based on the credential.
if (mConfig.getCredential().getUserCredential() != null) {
@@ -311,6 +313,7 @@
mConfig.getCredential().getSimCredential());
}
wifiConfig.enterpriseConfig = enterpriseConfig;
+ wifiConfig.shared = mIsShared;
return wifiConfig;
}
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..c45a284
--- /dev/null
+++ b/service/java/com/android/server/wifi/hotspot2/PasspointProvisioner.java
@@ -0,0 +1,435 @@
+/*
+ * 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;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+/**
+ * Provides methods to carry out provisioning flow
+ */
+public class PasspointProvisioner {
+ private static final String TAG = "PasspointProvisioner";
+
+ // Indicates callback type for caller initiating provisioning
+ private static final int PROVISIONING_STATUS = 0;
+ private static final int PROVISIONING_FAILURE = 1;
+
+ // TLS version to be used for HTTPS connection with OSU server
+ private static final String TLS_VERSION = "TLSv1";
+
+ private final Context mContext;
+ private final ProvisioningStateMachine mProvisioningStateMachine;
+ private final OsuNetworkCallbacks mOsuNetworkCallbacks;
+ private final OsuNetworkConnection mOsuNetworkConnection;
+ private final OsuServerConnection mOsuServerConnection;
+
+ private int mCurrentSessionId = 0;
+ private int mCallingUid;
+ private boolean mVerboseLoggingEnabled = false;
+
+ PasspointProvisioner(Context context, OsuNetworkConnection osuNetworkConnection,
+ OsuServerConnection osuServerConnection) {
+ mContext = context;
+ mOsuNetworkConnection = osuNetworkConnection;
+ mProvisioningStateMachine = new ProvisioningStateMachine();
+ mOsuNetworkCallbacks = new OsuNetworkCallbacks();
+ mOsuServerConnection = osuServerConnection;
+ }
+
+ /**
+ * 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());
+ mOsuServerConnection.init(TLS_VERSION);
+ }
+
+ /**
+ * 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);
+ mOsuServerConnection.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 INITIAL_STATE = 1;
+ private static final int WAITING_TO_CONNECT = 2;
+ private static final int OSU_AP_CONNECTED = 3;
+ private static final int OSU_SERVER_CONNECTED = 4;
+ private static final int OSU_SERVER_VALIDATED = 5;
+ private static final int OSU_PROVIDER_VERIFIED = 6;
+
+ private OsuProvider mOsuProvider;
+ private IProvisioningCallback mProvisioningCallback;
+ private int mState = INITIAL_STATE;
+ private Handler mHandler;
+ private URL mServerUrl;
+
+ /**
+ * Initializes and starts the state machine with a handler to handle incoming events
+ */
+ public void start(Handler handler) {
+ mHandler = handler;
+ }
+
+ /**
+ * 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) {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "State Machine needs to be reset before starting provisioning");
+ }
+ resetStateMachine(ProvisioningCallback.OSU_FAILURE_PROVISIONING_ABORTED);
+ }
+ if (!mOsuServerConnection.canValidateServer()) {
+ Log.w(TAG, "Provisioning is not possible");
+ mProvisioningCallback = callback;
+ resetStateMachine(ProvisioningCallback.OSU_FAILURE_PROVISIONING_NOT_AVAILABLE);
+ return;
+ }
+ URL serverUrl = null;
+ try {
+ serverUrl = new URL(provider.getServerUri().toString());
+ } catch (MalformedURLException e) {
+ Log.e(TAG, "Invalid Server URL");
+ mProvisioningCallback = callback;
+ resetStateMachine(ProvisioningCallback.OSU_FAILURE_SERVER_URL_INVALID);
+ return;
+ }
+ mServerUrl = serverUrl;
+ mProvisioningCallback = callback;
+ mOsuProvider = provider;
+ // Register for network and wifi state events during provisioning flow
+ mOsuNetworkConnection.setEventCallback(mOsuNetworkCallbacks);
+
+ // Register for OSU server callbacks
+ mOsuServerConnection.setEventCallback(new OsuServerCallbacks(++mCurrentSessionId));
+
+ if (!mOsuNetworkConnection.connect(mOsuProvider.getOsuSsid(),
+ mOsuProvider.getNetworkAccessIdentifier())) {
+ resetStateMachine(ProvisioningCallback.OSU_FAILURE_AP_CONNECTION);
+ return;
+ }
+ invokeProvisioningCallback(PROVISIONING_STATUS,
+ ProvisioningCallback.OSU_STATUS_AP_CONNECTING);
+ changeState(WAITING_TO_CONNECT);
+ }
+
+ /**
+ * Handle Wifi Disable event
+ */
+ public void handleWifiDisabled() {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "Wifi Disabled in state=" + mState);
+ }
+ if (mState == INITIAL_STATE) {
+ Log.w(TAG, "Wifi Disable unhandled in state=" + mState);
+ return;
+ }
+ resetStateMachine(ProvisioningCallback.OSU_FAILURE_AP_CONNECTION);
+ }
+
+ /**
+ * Handle server validation failure
+ */
+ public void handleServerValidationFailure(int sessionId) {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "Server Validation failure received in " + mState);
+ }
+ if (sessionId != mCurrentSessionId) {
+ Log.w(TAG, "Expected server validation callback for currentSessionId="
+ + mCurrentSessionId);
+ return;
+ }
+ if (mState != OSU_SERVER_CONNECTED) {
+ Log.wtf(TAG, "Server Validation Failure unhandled in mState=" + mState);
+ return;
+ }
+ resetStateMachine(ProvisioningCallback.OSU_FAILURE_SERVER_VALIDATION);
+ }
+
+ /**
+ * Handle status of server validation success
+ */
+ public void handleServerValidationSuccess(int sessionId) {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "Server Validation Success received in " + mState);
+ }
+ if (sessionId != mCurrentSessionId) {
+ Log.w(TAG, "Expected server validation callback for currentSessionId="
+ + mCurrentSessionId);
+ return;
+ }
+ if (mState != OSU_SERVER_CONNECTED) {
+ Log.wtf(TAG, "Server validation success event unhandled in state=" + mState);
+ return;
+ }
+ changeState(OSU_SERVER_VALIDATED);
+ invokeProvisioningCallback(PROVISIONING_STATUS,
+ ProvisioningCallback.OSU_STATUS_SERVER_VALIDATED);
+ validateProvider();
+ }
+
+ private void validateProvider() {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "Validating provider in state=" + mState);
+ }
+ if (!mOsuServerConnection.validateProvider(mOsuProvider.getFriendlyName())) {
+ resetStateMachine(ProvisioningCallback.OSU_FAILURE_PROVIDER_VERIFICATION);
+ return;
+ }
+ changeState(OSU_PROVIDER_VERIFIED);
+ invokeProvisioningCallback(PROVISIONING_STATUS,
+ ProvisioningCallback.OSU_STATUS_PROVIDER_VERIFIED);
+ // TODO(sohanirao) : send Initial SOAP Exchange
+ }
+
+ /**
+ * 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.wtf(TAG, "Connection event unhandled in state=" + mState);
+ return;
+ }
+ invokeProvisioningCallback(PROVISIONING_STATUS,
+ ProvisioningCallback.OSU_STATUS_AP_CONNECTED);
+ changeState(OSU_AP_CONNECTED);
+ initiateServerConnection(network);
+ }
+
+ private void initiateServerConnection(Network network) {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "Initiating server connection in state=" + mState);
+ }
+ if (mState != OSU_AP_CONNECTED) {
+ Log.wtf(TAG , "Initiating server connection aborted in invalid state=" + mState);
+ return;
+ }
+ if (!mOsuServerConnection.connect(mServerUrl, network)) {
+ resetStateMachine(ProvisioningCallback.OSU_FAILURE_SERVER_CONNECTION);
+ return;
+ }
+ changeState(OSU_SERVER_CONNECTED);
+ invokeProvisioningCallback(PROVISIONING_STATUS,
+ ProvisioningCallback.OSU_STATUS_SERVER_CONNECTED);
+ }
+
+ /**
+ * Disconnect event received
+ */
+ public void handleDisconnect() {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "Connection failed in state=" + mState);
+ }
+ if (mState == INITIAL_STATE) {
+ Log.w(TAG, "Disconnect event unhandled in state=" + mState);
+ return;
+ }
+ resetStateMachine(ProvisioningCallback.OSU_FAILURE_AP_CONNECTION);
+ }
+
+ private void invokeProvisioningCallback(int callbackType, int status) {
+ if (mProvisioningCallback == null) {
+ Log.e(TAG, "Provisioning callback " + callbackType + " with status " + status
+ + " not invoked");
+ return;
+ }
+ try {
+ if (callbackType == PROVISIONING_STATUS) {
+ mProvisioningCallback.onProvisioningStatus(status);
+ } else {
+ mProvisioningCallback.onProvisioningFailure(status);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Remote Exception while posting callback type=" + callbackType
+ + " status=" + status);
+ }
+ }
+
+ private void changeState(int nextState) {
+ if (nextState != mState) {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "Changing state from " + mState + " -> " + nextState);
+ }
+ mState = nextState;
+ }
+ }
+
+ private void resetStateMachine(int failureCode) {
+ invokeProvisioningCallback(PROVISIONING_FAILURE, failureCode);
+ mOsuNetworkConnection.setEventCallback(null);
+ mOsuNetworkConnection.disconnectIfNeeded();
+ mOsuServerConnection.setEventCallback(null);
+ mOsuServerConnection.cleanup();
+ changeState(INITIAL_STATE);
+ }
+ }
+
+ /**
+ * Callbacks for network and wifi events
+ */
+ class OsuNetworkCallbacks implements OsuNetworkConnection.Callbacks {
+
+ OsuNetworkCallbacks() {}
+
+ @Override
+ public void onConnected(Network network) {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "onConnected to " + network);
+ }
+ if (network == null) {
+ mProvisioningStateMachine.handleDisconnect();
+ } else {
+ mProvisioningStateMachine.handleConnectedEvent(network);
+ }
+ }
+
+ @Override
+ public void onDisconnected() {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "onDisconnected");
+ }
+ mProvisioningStateMachine.handleDisconnect();
+ }
+
+ @Override
+ public void onTimeOut() {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "Timed out waiting for connection to OSU AP");
+ }
+ mProvisioningStateMachine.handleDisconnect();
+ }
+
+ @Override
+ public void onWifiEnabled() {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "onWifiEnabled");
+ }
+ }
+
+ @Override
+ public void onWifiDisabled() {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "onWifiDisabled");
+ }
+ mProvisioningStateMachine.handleWifiDisabled();
+ }
+ }
+
+ /**
+ * Defines the callbacks expected from OsuServerConnection
+ */
+ public class OsuServerCallbacks {
+ private final int mSessionId;
+
+ OsuServerCallbacks(int sessionId) {
+ mSessionId = sessionId;
+ }
+
+ /**
+ * Returns the session ID corresponding to this callback
+ * @return int sessionID
+ */
+ public int getSessionId() {
+ return mSessionId;
+ }
+
+ /**
+ * Provides a server validation status for the session ID
+ * @param sessionId integer indicating current session ID
+ * @param succeeded boolean indicating success/failure of server validation
+ */
+ public void onServerValidationStatus(int sessionId, boolean succeeded) {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "OSU Server Validation status=" + succeeded + " sessionId=" + sessionId);
+ }
+ if (succeeded) {
+ mProvisioningStateMachine.getHandler().post(() -> {
+ mProvisioningStateMachine.handleServerValidationSuccess(sessionId);
+ });
+ } else {
+ mProvisioningStateMachine.getHandler().post(() -> {
+ mProvisioningStateMachine.handleServerValidationFailure(sessionId);
+ });
+ }
+ }
+
+ }
+}
+
diff --git a/service/java/com/android/server/wifi/p2p/SupplicantP2pIfaceHal.java b/service/java/com/android/server/wifi/p2p/SupplicantP2pIfaceHal.java
index 50f2ccf..366b0a1 100644
--- a/service/java/com/android/server/wifi/p2p/SupplicantP2pIfaceHal.java
+++ b/service/java/com/android/server/wifi/p2p/SupplicantP2pIfaceHal.java
@@ -231,70 +231,133 @@
private boolean initSupplicantP2pIface() {
synchronized (mLock) {
- /** List all supplicant Ifaces */
- final ArrayList<ISupplicant.IfaceInfo> supplicantIfaces = new ArrayList();
- try {
- mISupplicant.listInterfaces((SupplicantStatus status,
- ArrayList<ISupplicant.IfaceInfo> ifaces) -> {
- if (status.code != SupplicantStatusCode.SUCCESS) {
- Log.e(TAG, "Getting Supplicant Interfaces failed: " + status.code);
- return;
- }
- supplicantIfaces.addAll(ifaces);
- });
- } catch (RemoteException e) {
- Log.e(TAG, "ISupplicant.listInterfaces exception: " + e);
+ ISupplicantIface ifaceHwBinder;
+ if (isV1_1()) {
+ ifaceHwBinder = addIfaceV1_1();
+ } else {
+ ifaceHwBinder = getIfaceV1_0();
+ }
+ if (ifaceHwBinder == null) {
+ Log.e(TAG, "initSupplicantP2pIface got null iface");
return false;
}
- if (supplicantIfaces.size() == 0) {
- Log.e(TAG, "Got zero HIDL supplicant ifaces. Stopping supplicant HIDL startup.");
+ mISupplicantP2pIface = getP2pIfaceMockable(ifaceHwBinder);
+ if (!linkToSupplicantP2pIfaceDeath()) {
return false;
}
- SupplicantResult<ISupplicantIface> supplicantIface =
- new SupplicantResult("getInterface()");
- for (ISupplicant.IfaceInfo ifaceInfo : supplicantIfaces) {
- if (ifaceInfo.type == IfaceType.P2P) {
- try {
- mISupplicant.getInterface(ifaceInfo,
- (SupplicantStatus status, ISupplicantIface iface) -> {
+ if (mISupplicantP2pIface != null && mMonitor != null) {
+ // TODO(ender): Get rid of hard-coded interface name, which is
+ // assumed to be the group interface name in several other classes
+ // ("p2p0" should probably become getName()).
+ mCallback = new SupplicantP2pIfaceCallback("p2p0", mMonitor);
+ if (!registerCallback(mCallback)) {
+ Log.e(TAG, "Callback registration failed. Initialization incomplete.");
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ private ISupplicantIface getIfaceV1_0() {
+ /** List all supplicant Ifaces */
+ final ArrayList<ISupplicant.IfaceInfo> supplicantIfaces = new ArrayList();
+ try {
+ mISupplicant.listInterfaces((SupplicantStatus status,
+ ArrayList<ISupplicant.IfaceInfo> ifaces) -> {
+ if (status.code != SupplicantStatusCode.SUCCESS) {
+ Log.e(TAG, "Getting Supplicant Interfaces failed: " + status.code);
+ return;
+ }
+ supplicantIfaces.addAll(ifaces);
+ });
+ } catch (RemoteException e) {
+ Log.e(TAG, "ISupplicant.listInterfaces exception: " + e);
+ return null;
+ }
+ if (supplicantIfaces.size() == 0) {
+ Log.e(TAG, "Got zero HIDL supplicant ifaces. Stopping supplicant HIDL startup.");
+ supplicantServiceDiedHandler();
+ return null;
+ }
+ SupplicantResult<ISupplicantIface> supplicantIface =
+ new SupplicantResult("getInterface()");
+ for (ISupplicant.IfaceInfo ifaceInfo : supplicantIfaces) {
+ if (ifaceInfo.type == IfaceType.P2P) {
+ try {
+ mISupplicant.getInterface(ifaceInfo,
+ (SupplicantStatus status, ISupplicantIface iface) -> {
if (status.code != SupplicantStatusCode.SUCCESS) {
Log.e(TAG, "Failed to get ISupplicantIface " + status.code);
return;
}
supplicantIface.setResult(status, iface);
});
- } catch (RemoteException e) {
- Log.e(TAG, "ISupplicant.getInterface exception: " + e);
- return false;
- }
- break;
+ } catch (RemoteException e) {
+ Log.e(TAG, "ISupplicant.getInterface exception: " + e);
+ supplicantServiceDiedHandler();
+ return null;
}
- }
-
- if (supplicantIface.getResult() == null) {
- Log.e(TAG, "initSupplicantP2pIface got null iface");
- return false;
- }
- mISupplicantP2pIface = getP2pIfaceMockable(supplicantIface.getResult());
- if (!linkToSupplicantP2pIfaceDeath()) {
- return false;
+ break;
}
}
-
- if (mISupplicantP2pIface != null && mMonitor != null) {
- // TODO(ender): Get rid of hard-coded interface name, which is
- // assumed to be the group interface name in several other classes
- // ("p2p0" should probably become getName()).
- mCallback = new SupplicantP2pIfaceCallback("p2p0", mMonitor);
- if (!registerCallback(mCallback)) {
- Log.e(TAG, "Callback registration failed. Initialization incomplete.");
- return false;
- }
- }
-
- return true;
+ return supplicantIface.getResult();
}
+ private ISupplicantIface addIfaceV1_1() {
+ synchronized (mLock) {
+ ISupplicant.IfaceInfo ifaceInfo = new ISupplicant.IfaceInfo();
+ ifaceInfo.name = "p2p0";
+ ifaceInfo.type = IfaceType.P2P;
+ SupplicantResult<ISupplicantIface> supplicantIface =
+ new SupplicantResult("addInterface(" + ifaceInfo + ")");
+ try {
+ getSupplicantMockableV1_1().addInterface(ifaceInfo,
+ (SupplicantStatus status, ISupplicantIface iface) -> {
+ if (status.code != SupplicantStatusCode.SUCCESS
+ && status.code != SupplicantStatusCode.FAILURE_IFACE_EXISTS) {
+ Log.e(TAG, "Failed to get ISupplicantIface " + status.code);
+ return;
+ }
+ supplicantIface.setResult(status, iface);
+ });
+ } catch (RemoteException e) {
+ Log.e(TAG, "ISupplicant.addInterface exception: " + e);
+ supplicantServiceDiedHandler();
+ return null;
+ }
+ return supplicantIface.getResult();
+ }
+ }
+
+ /**
+ * Teardown the P2P interface.
+ *
+ * @return true on success, false otherwise.
+ */
+ public boolean removeIfaceV1_1() {
+ synchronized (mLock) {
+ try {
+ ISupplicant.IfaceInfo ifaceInfo = new ISupplicant.IfaceInfo();
+ ifaceInfo.name = "p2p0";
+ ifaceInfo.type = IfaceType.P2P;
+ SupplicantStatus status =
+ android.hardware.wifi.supplicant.V1_1.ISupplicant.castFrom(mISupplicant)
+ .removeInterface(ifaceInfo);
+ if (status.code != SupplicantStatusCode.SUCCESS) {
+ Log.e(TAG, "Failed to remove iface " + status.code);
+ return false;
+ }
+ mCallback = null;
+ } catch (RemoteException e) {
+ Log.e(TAG, "ISupplicant.removeInterface exception: " + e);
+ supplicantServiceDiedHandler();
+ return false;
+ }
+ mISupplicantP2pIface = null;
+ return true;
+ }
+ }
private void supplicantServiceDiedHandler() {
synchronized (mLock) {
mISupplicant = null;
@@ -307,7 +370,9 @@
* Signals whether Initialization completed successfully.
*/
public boolean isInitializationStarted() {
- return mIServiceManager != null;
+ synchronized (mLock) {
+ return mIServiceManager != null;
+ }
}
/**
@@ -329,6 +394,14 @@
return ISupplicant.getService();
}
+ protected android.hardware.wifi.supplicant.V1_1.ISupplicant getSupplicantMockableV1_1()
+ throws RemoteException {
+ synchronized (mLock) {
+ return android.hardware.wifi.supplicant.V1_1.ISupplicant.castFrom(
+ ISupplicant.getService());
+ }
+ }
+
protected ISupplicantP2pIface getP2pIfaceMockable(ISupplicantIface iface) {
return ISupplicantP2pIface.asInterface(iface.asBinder());
}
@@ -337,6 +410,22 @@
return ISupplicantP2pNetwork.asInterface(network.asBinder());
}
+ /**
+ * Check if the device is running V1_1 supplicant service.
+ * @return
+ */
+ private boolean isV1_1() {
+ synchronized (mLock) {
+ try {
+ return (getSupplicantMockableV1_1() != null);
+ } catch (RemoteException e) {
+ Log.e(TAG, "ISupplicant.getService exception: " + e);
+ supplicantServiceDiedHandler();
+ return false;
+ }
+ }
+ }
+
protected static void logd(String s) {
if (DBG) Log.d(TAG, s);
}
@@ -2227,7 +2316,9 @@
}
public boolean isSuccess() {
- return (mStatus != null && mStatus.code == SupplicantStatusCode.SUCCESS);
+ return (mStatus != null
+ && (mStatus.code == SupplicantStatusCode.SUCCESS
+ || mStatus.code == SupplicantStatusCode.FAILURE_IFACE_EXISTS));
}
public E getResult() {
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..d00bf75
--- /dev/null
+++ b/service/java/com/android/server/wifi/rtt/RttNative.java
@@ -0,0 +1,332 @@
+/*
+ * 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
+ /* package */ boolean mDbg = false;
+
+ 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 (mDbg) 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.enableIfPossible();
+ }
+ }
+ }
+
+ /**
+ * 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 (mDbg) {
+ Log.v(TAG,
+ "rangeRequest: cmdId=" + cmdId + ", # of requests=" + request.mRttPeers.size());
+ }
+ if (VDBG) Log.v(TAG, "rangeRequest: 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 (mDbg) 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 (mDbg) 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();
+
+ System.arraycopy(responder.macAddress.toByteArray(), 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..fabab89
--- /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_RTT_RANGING_SERVICE);
+ publishBinderService(Context.WIFI_RTT_RANGING_SERVICE, mImpl);
+ }
+
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
+ Log.i(TAG, "Starting " + Context.WIFI_RTT_RANGING_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, wifiInjector.getFrameworkFacade());
+ }
+ }
+}
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..16275c1
--- /dev/null
+++ b/service/java/com/android/server/wifi/rtt/RttServiceImpl.java
@@ -0,0 +1,955 @@
+/*
+ * 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.database.ContentObserver;
+import android.hardware.wifi.V1_0.RttResult;
+import android.hardware.wifi.V1_0.RttStatus;
+import android.location.LocationManager;
+import android.net.MacAddress;
+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.provider.Settings;
+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.FrameworkFacade;
+import com.android.server.wifi.util.WifiPermissionsUtil;
+
+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 boolean mDbg = false;
+
+ private final Context mContext;
+ private Clock mClock;
+ private IWifiAwareManager mAwareBinder;
+ private RttNative mRttNative;
+ private WifiPermissionsUtil mWifiPermissionsUtil;
+ private ActivityManager mActivityManager;
+ private PowerManager mPowerManager;
+ private FrameworkFacade mFrameworkFacade;
+
+ 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.
+ * @param frameworkFacade Facade for framework classes, allows mocking.
+ */
+ public void start(Looper looper, Clock clock, IWifiAwareManager awareBinder,
+ RttNative rttNative, WifiPermissionsUtil wifiPermissionsUtil,
+ FrameworkFacade frameworkFacade) {
+ mClock = clock;
+ mAwareBinder = awareBinder;
+ mRttNative = rttNative;
+ mWifiPermissionsUtil = wifiPermissionsUtil;
+ mFrameworkFacade = frameworkFacade;
+ 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 (mDbg) Log.v(TAG, "BroadcastReceiver: action=" + action);
+
+ if (PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)) {
+ if (mPowerManager.isDeviceIdleMode()) {
+ disable();
+ } else {
+ enableIfPossible();
+ }
+ }
+ }
+ }, intentFilter);
+
+ frameworkFacade.registerContentObserver(mContext,
+ Settings.Global.getUriFor(Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED), true,
+ new ContentObserver(mRttServiceSynchronized.mHandler) {
+ @Override
+ public void onChange(boolean selfChange) {
+ enableVerboseLogging(frameworkFacade.getIntegerSetting(mContext,
+ Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, 0));
+ }
+ });
+ enableVerboseLogging(frameworkFacade.getIntegerSetting(mContext,
+ Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, 0));
+
+ intentFilter = new IntentFilter();
+ intentFilter.addAction(LocationManager.MODE_CHANGED_ACTION);
+ mContext.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (mDbg) Log.v(TAG, "onReceive: MODE_CHANGED_ACTION: intent=" + intent);
+ int locationMode = mFrameworkFacade.getSecureIntegerSetting(mContext,
+ Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF);
+ if (locationMode == Settings.Secure.LOCATION_MODE_HIGH_ACCURACY
+ || locationMode == Settings.Secure.LOCATION_MODE_BATTERY_SAVING) {
+ enableIfPossible();
+ } else {
+ disable();
+ }
+ }
+ }, intentFilter);
+
+ mRttServiceSynchronized.mHandler.post(() -> {
+ rttNative.start();
+ });
+ }
+
+ private void enableVerboseLogging(int verbose) {
+ if (verbose > 0) {
+ mDbg = true;
+ } else {
+ mDbg = false;
+ }
+ if (VDBG) {
+ mDbg = true; // just override
+ }
+ mRttNative.mDbg = mDbg;
+ }
+
+ /*
+ * 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 if possible: broadcast notification & start launching any queued requests
+ *
+ * If possible:
+ * - RTT HAL is available
+ * - Not in Idle mode
+ * - Location Mode allows Wi-Fi based locationing
+ */
+ public void enableIfPossible() {
+ boolean isAvailable = isAvailable();
+ if (VDBG) Log.v(TAG, "enableIfPossible: isAvailable=" + isAvailable);
+ if (!isAvailable) {
+ return;
+ }
+ 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() {
+ int locationMode = mFrameworkFacade.getSecureIntegerSetting(mContext,
+ Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF);
+ return mRttNative.isReady() && !mPowerManager.isDeviceIdleMode() && (
+ locationMode == Settings.Secure.LOCATION_MODE_HIGH_ACCURACY
+ || locationMode == Settings.Secure.LOCATION_MODE_BATTERY_SAVING);
+ }
+
+ /**
+ * 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();
+ mWifiPermissionsUtil.enforceLocationPermission(callingPackage, uid);
+ if (workSource != null) {
+ enforceLocationHardware();
+ }
+
+ // register for binder death
+ IBinder.DeathRecipient dr = new IBinder.DeathRecipient() {
+ @Override
+ public void binderDied() {
+ if (mDbg) 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);
+ return;
+ }
+
+ 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 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) {
+ macAddresses.add(peer.macAddress.toByteArray());
+ }
+
+ 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 (mDbg) {
+ 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);
+ }
+
+ RangingRequest.Builder newRequestBuilder = new RangingRequest.Builder();
+ for (ResponderConfig rttPeer : request.request.mRttPeers) {
+ if (rttPeer.peerHandle != null && rttPeer.macAddress == null) {
+ newRequestBuilder.addResponder(new ResponderConfig(
+ MacAddress.fromBytes(peerIdToMacMap.get(rttPeer.peerHandle.peerId)),
+ rttPeer.peerHandle, rttPeer.responderType, rttPeer.supports80211mc,
+ rttPeer.channelWidth, rttPeer.frequency, rttPeer.centerFreq0,
+ rttPeer.centerFreq1, rttPeer.preamble));
+ } else {
+ newRequestBuilder.addResponder(rttPeer);
+ }
+ }
+ request.request = newRequestBuilder.build();
+
+ // 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);
+ int locationMode = mFrameworkFacade.getSecureIntegerSetting(mContext,
+ Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF);
+ if (locationMode != Settings.Secure.LOCATION_MODE_HIGH_ACCURACY
+ && locationMode != Settings.Secure.LOCATION_MODE_BATTERY_SAVING) {
+ permissionGranted = false;
+ }
+ 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<MacAddress, RttResult> resultEntries = new HashMap<>();
+ for (RttResult result : results) {
+ resultEntries.put(MacAddress.fromBytes(result.addr), result);
+ }
+
+ List<RangingResult> finalResults = new ArrayList<>(request.mRttPeers.size());
+
+ for (ResponderConfig peer : request.mRttPeers) {
+ RttResult resultForRequest = resultEntries.get(peer.macAddress);
+ if (resultForRequest == null) {
+ if (mDbg) {
+ Log.v(TAG, "postProcessResults: missing=" + 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..05fdfbc 100644
--- a/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java
+++ b/service/java/com/android/server/wifi/scanner/WifiScanningServiceImpl.java
@@ -16,13 +16,15 @@
package com.android.server.wifi.scanner;
+import static android.content.pm.PackageManager.PERMISSION_DENIED;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
import android.Manifest;
import android.app.AlarmManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.PackageManager;
import android.net.wifi.IWifiScanner;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiManager;
@@ -75,7 +77,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 +241,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;
@@ -328,29 +325,24 @@
mClientHandler.setWifiLog(log);
}
- private static boolean isWorkSourceValid(WorkSource workSource) {
- return workSource != null && workSource.size() > 0 && workSource.get(0) >= 0;
- }
-
private WorkSource computeWorkSource(ClientInfo ci, WorkSource requestedWorkSource) {
if (requestedWorkSource != null) {
- if (isWorkSourceValid(requestedWorkSource)) {
- // Wifi currently doesn't use names, so need to clear names out of the
- // supplied WorkSource to allow future WorkSource combining.
- requestedWorkSource.clearNames();
+ requestedWorkSource.clearNames();
+
+ if (!requestedWorkSource.isEmpty()) {
return requestedWorkSource;
- } else {
- loge("Got invalid work source request: " + requestedWorkSource.toString() +
- " from " + ci);
}
}
- WorkSource callingWorkSource = new WorkSource(ci.getUid());
- if (isWorkSourceValid(callingWorkSource)) {
- return callingWorkSource;
- } else {
- loge("Client has invalid work source: " + callingWorkSource);
- return new WorkSource();
+
+ if (ci.getUid() > 0) {
+ return new WorkSource(ci.getUid());
}
+
+ // We can't construct a sensible WorkSource because the one supplied to us was empty and
+ // we don't have a valid UID for the given client.
+ loge("Unable to compute workSource for client: " + ci + ", requested: "
+ + requestedWorkSource);
+ return new WorkSource();
}
private class RequestInfo<T> {
@@ -608,7 +600,7 @@
scanParams.getParcelable(WifiScanner.SCAN_PARAMS_SCAN_SETTINGS_KEY);
WorkSource workSource =
scanParams.getParcelable(WifiScanner.SCAN_PARAMS_WORK_SOURCE_KEY);
- if (validateScanRequest(ci, handler, scanSettings, workSource)) {
+ if (validateScanRequest(ci, handler, scanSettings)) {
logScanRequest("addSingleScanRequest", ci, handler, workSource,
scanSettings, null);
replySucceeded(msg);
@@ -714,8 +706,7 @@
}
}
- boolean validateScanRequest(ClientInfo ci, int handler, ScanSettings settings,
- WorkSource workSource) {
+ boolean validateScanRequest(ClientInfo ci, int handler, ScanSettings settings) {
if (ci == null) {
Log.d(TAG, "Failing single scan request ClientInfo not found " + handler);
return false;
@@ -726,6 +717,20 @@
return false;
}
}
+ if (mContext.checkPermission(
+ Manifest.permission.NETWORK_STACK, UNKNOWN_PID, ci.getUid())
+ == PERMISSION_DENIED) {
+ if (!ArrayUtils.isEmpty(settings.hiddenNetworks)) {
+ Log.e(TAG, "Failing single scan because app " + ci.getUid()
+ + " does not have permission to set hidden networks");
+ return false;
+ }
+ if (settings.type != WifiScanner.TYPE_LOW_LATENCY) {
+ Log.e(TAG, "Failing single scan because app " + ci.getUid()
+ + " does not have permission to set type");
+ return false;
+ }
+ }
return true;
}
@@ -1341,7 +1346,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 +1357,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 +1367,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 +1384,6 @@
addState(mStartedState, mDefaultState);
addState(mHwPnoScanState, mStartedState);
addState(mSingleScanState, mHwPnoScanState);
- addState(mSwPnoScanState, mStartedState);
// CHECKSTYLE:ON IndentationCheck
setInitialState(mDefaultState);
@@ -1466,12 +1463,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 +1578,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 +1658,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 +1670,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 +1692,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) {
@@ -1867,7 +1761,7 @@
// This has to be implemented by subclasses to report events back to clients.
public abstract void reportEvent(int what, int arg1, int arg2, Object obj);
- // TODO(b/27903217): Blame scan on provided work source
+ // TODO(b/27903217, 71530998): This is dead code. Should this be wired up ?
private void reportBatchedScanStart() {
if (mUid == 0)
return;
@@ -1881,6 +1775,7 @@
}
}
+ // TODO(b/27903217, 71530998): This is dead code. Should this be wired up ?
private void reportBatchedScanStop() {
if (mUid == 0)
return;
@@ -1907,7 +1802,8 @@
return totalScanDurationPerHour / ChannelHelper.SCAN_PERIOD_PER_CHANNEL_MS;
}
- public void reportScanWorkUpdate() {
+ // TODO(b/27903217, 71530998): This is dead code. Should this be wired up ?
+ private void reportScanWorkUpdate() {
if (mScanWorkReported) {
reportBatchedScanStop();
mScanWorkReported = false;
@@ -2079,7 +1975,7 @@
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
- != PackageManager.PERMISSION_GRANTED) {
+ != PERMISSION_GRANTED) {
pw.println("Permission Denial: can't dump WifiScanner from from pid="
+ Binder.getCallingPid()
+ ", uid=" + Binder.getCallingUid()
@@ -2213,7 +2109,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..9afe061 100644
--- a/service/java/com/android/server/wifi/scanner/WificondScannerImpl.java
+++ b/service/java/com/android/server/wifi/scanner/WificondScannerImpl.java
@@ -34,9 +34,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.util.ArrayDeque;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
@@ -50,7 +48,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;
@@ -68,39 +65,16 @@
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]);
- // Settings for the currently running scan, null if no scan active
+ // Settings for the currently running single scan, null if no scan active
private LastScanSettings mLastScanSettings = null;
+ // Settings for the currently running pno scan, null if no scan active
+ private LastPnoScanSettings mLastPnoScanSettings = null;
- // Pno related info.
- private WifiNative.PnoSettings mPnoSettings = null;
- private WifiNative.PnoEventHandler mPnoEventHandler;
private final boolean mHwPnoScanSupported;
- private final HwPnoDebouncer mHwPnoDebouncer;
- private final HwPnoDebouncer.Listener mHwPnoDebouncerListener = new HwPnoDebouncer.Listener() {
- public void onPnoScanFailed() {
- Log.e(TAG, "Pno scan failure received");
- reportPnoScanFailure();
- }
- };
/**
* Duration to wait before timing out a scan.
@@ -110,14 +84,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) {
@@ -135,7 +101,6 @@
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
mEventHandler = new Handler(looper, this);
mClock = clock;
- mHwPnoDebouncer = new HwPnoDebouncer(mWifiNative, mAlarmManager, mEventHandler, mClock);
// Check if the device supports HW PNO scans.
mHwPnoScanSupported = mContext.getResources().getBoolean(
@@ -149,20 +114,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
+ mLastPnoScanSettings = null; // finally clear any active scan
}
}
@@ -189,15 +146,66 @@
+ ",eventHandler=" + eventHandler);
return false;
}
- if (mPendingSingleScanSettings != null
- || (mLastScanSettings != null && mLastScanSettings.singleScanActive)) {
- Log.w(TAG, "A single scan is already running");
- return false;
- }
synchronized (mSettingsLock) {
- mPendingSingleScanSettings = settings;
- mPendingSingleScanEventHandler = eventHandler;
- processPendingScans();
+ if (mLastScanSettings != null) {
+ Log.w(TAG, "A single scan is already running");
+ return false;
+ }
+
+ ChannelCollection allFreqs = mChannelHelper.createChannelCollection();
+ boolean reportFullResults = false;
+
+ for (int i = 0; i < settings.num_buckets; ++i) {
+ WifiNative.BucketSettings bucketSettings = settings.buckets[i];
+ if ((bucketSettings.report_events
+ & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) != 0) {
+ reportFullResults = true;
+ }
+ allFreqs.addChannels(bucketSettings);
+ }
+
+ Set<String> hiddenNetworkSSIDSet = new HashSet<>();
+ if (settings.hiddenNetworks != null) {
+ int numHiddenNetworks =
+ Math.min(settings.hiddenNetworks.length, MAX_HIDDEN_NETWORK_IDS_PER_SCAN);
+ for (int i = 0; i < numHiddenNetworks; i++) {
+ hiddenNetworkSSIDSet.add(settings.hiddenNetworks[i].ssid);
+ }
+ }
+ mLastScanSettings = new LastScanSettings(
+ mClock.getElapsedSinceBootMillis(),
+ reportFullResults, allFreqs, eventHandler);
+
+ boolean success = false;
+ Set<Integer> freqs;
+ if (!allFreqs.isEmpty()) {
+ freqs = allFreqs.getScanFreqs();
+ success = mWifiNative.scan(freqs, hiddenNetworkSSIDSet);
+ if (!success) {
+ Log.e(TAG, "Failed to start scan, freqs=" + freqs);
+ }
+ } else {
+ // There is a scan request but no available channels could be scanned for.
+ // We regard it as a scan failure in this case.
+ Log.e(TAG, "Failed to start scan because there is no available channel to scan");
+ }
+ if (success) {
+ if (DBG) {
+ Log.d(TAG, "Starting wifi scan for freqs=" + freqs);
+ }
+
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ mClock.getElapsedSinceBootMillis() + SCAN_TIMEOUT_MS,
+ TIMEOUT_ALARM_TAG, mScanTimeoutListener, mEventHandler);
+ } else {
+ // indicate scan failure async
+ mEventHandler.post(new Runnable() {
+ public void run() {
+ reportScanFailure();
+ }
+ });
+ }
+
return true;
}
}
@@ -210,285 +218,28 @@
@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() {
Log.e(TAG, "Timed out waiting for scan result from wificond");
reportScanFailure();
- processPendingScans();
- }
-
- private boolean isDifferentPnoScanSettings(LastScanSettings newScanSettings) {
- return (mLastScanSettings == null || !Arrays.equals(
- newScanSettings.pnoNetworkList, mLastScanSettings.pnoNetworkList));
- }
-
- private void processPendingScans() {
- synchronized (mSettingsLock) {
- // Wait for the active scan result to come back to reschedule other scans,
- // unless if HW pno scan is running. Hw PNO scans are paused it if there
- // are other pending scans,
- if (mLastScanSettings != null && !mLastScanSettings.hwPnoScanActive) {
- return;
- }
-
- ChannelCollection allFreqs = mChannelHelper.createChannelCollection();
- Set<String> hiddenNetworkSSIDSet = new HashSet<>();
- 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();
- for (int i = 0; i < mPendingSingleScanSettings.num_buckets; ++i) {
- WifiNative.BucketSettings bucketSettings =
- mPendingSingleScanSettings.buckets[i];
- if ((bucketSettings.report_events
- & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) != 0) {
- reportFullResults = true;
- }
- singleScanFreqs.addChannels(bucketSettings);
- allFreqs.addChannels(bucketSettings);
- }
- newScanSettings.setSingleScan(reportFullResults, singleScanFreqs,
- mPendingSingleScanEventHandler);
-
- WifiNative.HiddenNetwork[] hiddenNetworks =
- mPendingSingleScanSettings.hiddenNetworks;
- if (hiddenNetworks != null) {
- int numHiddenNetworks =
- Math.min(hiddenNetworks.length, MAX_HIDDEN_NETWORK_IDS_PER_SCAN);
- for (int i = 0; i < numHiddenNetworks; i++) {
- hiddenNetworkSSIDSet.add(hiddenNetworks[i].ssid);
- }
- }
-
- mPendingSingleScanSettings = null;
- mPendingSingleScanEventHandler = null;
- }
-
- if (newScanSettings.backgroundScanActive || newScanSettings.singleScanActive) {
- boolean success = false;
- Set<Integer> freqs;
- if (!allFreqs.isEmpty()) {
- pauseHwPnoScan();
- freqs = allFreqs.getScanFreqs();
- success = mWifiNative.scan(freqs, hiddenNetworkSSIDSet);
- if (!success) {
- Log.e(TAG, "Failed to start scan, freqs=" + freqs);
- }
- } else {
- // There is a scan request but no available channels could be scanned for.
- // We regard it as a scan failure in this case.
- Log.e(TAG, "Failed to start scan because there is "
- + "no available channel to scan for");
- }
- if (success) {
- // TODO handle scan timeout
- if (DBG) {
- Log.d(TAG, "Starting wifi scan for freqs=" + freqs
- + ", background=" + newScanSettings.backgroundScanActive
- + ", single=" + newScanSettings.singleScanActive);
- }
- mLastScanSettings = newScanSettings;
- mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
- mClock.getElapsedSinceBootMillis() + SCAN_TIMEOUT_MS,
- TIMEOUT_ALARM_TAG, mScanTimeoutListener, mEventHandler);
- } else {
- // indicate scan failure async
- mEventHandler.post(new Runnable() {
- public void run() {
- if (newScanSettings.singleScanEventHandler != null) {
- newScanSettings.singleScanEventHandler
- .onScanStatus(WifiNative.WIFI_SCAN_FAILED);
- }
- }
- });
- // TODO(b/27769665) background scans should be failed too if scans fail enough
- }
- } else if (isHwPnoScanRequired()) {
- newScanSettings.setHwPnoScan(mPnoSettings.networkList, mPnoEventHandler);
- boolean status;
- // If the PNO network list has changed from the previous request, ensure that
- // we bypass the debounce logic and restart PNO scan.
- if (isDifferentPnoScanSettings(newScanSettings)) {
- status = restartHwPnoScan(mPnoSettings);
- } else {
- status = startHwPnoScan(mPnoSettings);
- }
- if (status) {
- mLastScanSettings = newScanSettings;
- } else {
- Log.e(TAG, "Failed to start PNO scan");
- // indicate scan failure async
- mEventHandler.post(new Runnable() {
- public void run() {
- if (mPnoEventHandler != null) {
- mPnoEventHandler.onPnoScanFailed();
- }
- // Clean up PNO state, we don't want to continue PNO scanning.
- mPnoSettings = null;
- mPnoEventHandler = null;
- }
- });
- }
- }
- }
}
@Override
@@ -498,16 +249,13 @@
Log.w(TAG, "Scan failed");
mAlarmManager.cancel(mScanTimeoutListener);
reportScanFailure();
- processPendingScans();
break;
case WifiMonitor.PNO_SCAN_RESULTS_EVENT:
pollLatestScanDataForPno();
- processPendingScans();
break;
case WifiMonitor.SCAN_RESULTS_EVENT:
mAlarmManager.cancel(mScanTimeoutListener);
pollLatestScanData();
- processPendingScans();
break;
default:
// ignore unknown event
@@ -522,7 +270,6 @@
mLastScanSettings.singleScanEventHandler
.onScanStatus(WifiNative.WIFI_SCAN_FAILED);
}
- // TODO(b/27769665) background scans should be failed too if scans fail enough
mLastScanSettings = null;
}
}
@@ -530,21 +277,19 @@
private void reportPnoScanFailure() {
synchronized (mSettingsLock) {
- if (mLastScanSettings != null && mLastScanSettings.hwPnoScanActive) {
- if (mLastScanSettings.pnoScanEventHandler != null) {
- mLastScanSettings.pnoScanEventHandler.onPnoScanFailed();
+ if (mLastPnoScanSettings != null) {
+ if (mLastPnoScanSettings.pnoScanEventHandler != null) {
+ mLastPnoScanSettings.pnoScanEventHandler.onPnoScanFailed();
}
// Clean up PNO state, we don't want to continue PNO scanning.
- mPnoSettings = null;
- mPnoEventHandler = null;
- mLastScanSettings = null;
+ mLastPnoScanSettings = null;
}
}
}
private void pollLatestScanDataForPno() {
synchronized (mSettingsLock) {
- if (mLastScanSettings == null) {
+ if (mLastPnoScanSettings == null) {
// got a scan before we started scanning or after scan was canceled
return;
}
@@ -554,10 +299,8 @@
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.hwPnoScanActive) {
- hwPnoScanResults.add(result);
- }
+ if (timestamp_ms > mLastPnoScanSettings.startTime) {
+ hwPnoScanResults.add(result);
} else {
numFilteredScanResults++;
}
@@ -567,25 +310,11 @@
Log.d(TAG, "Filtering out " + numFilteredScanResults + " pno scan results.");
}
- if (mLastScanSettings.hwPnoScanActive
- && mLastScanSettings.pnoScanEventHandler != null) {
+ if (mLastPnoScanSettings.pnoScanEventHandler != null) {
ScanResult[] pnoScanResultsArray =
hwPnoScanResults.toArray(new ScanResult[hwPnoScanResults.size()]);
- mLastScanSettings.pnoScanEventHandler.onPnoNetworkFound(pnoScanResultsArray);
+ mLastPnoScanSettings.pnoScanEventHandler.onPnoNetworkFound(pnoScanResultsArray);
}
- // On pno scan result event, we are expecting a mLastScanSettings for pno scan.
- // However, if unlikey mLastScanSettings is for single scan, we need this part
- // to protect from leaving WifiSingleScanStateMachine in a forever wait state.
- if (mLastScanSettings.singleScanActive
- && mLastScanSettings.singleScanEventHandler != null) {
- Log.w(TAG, "Polling pno scan result when single scan is active, reporting"
- + " single scan failure");
- mLastScanSettings.singleScanEventHandler
- .onScanStatus(WifiNative.WIFI_SCAN_FAILED);
- }
- // mLastScanSettings is for either single/batched scan or pno scan.
- // We can safely set it to null when pno scan finishes.
- mLastScanSettings = null;
}
}
@@ -607,20 +336,14 @@
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(
+ if (mLastScanSettings.singleScanFreqs.containsChannel(
result.frequency)) {
singleScanResults.add(result);
}
@@ -632,51 +355,7 @@
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.singleScanEventHandler != null) {
if (mLastScanSettings.reportSingleScanFullResults) {
for (ScanResult scanResult : singleScanResults) {
// ignore buckets scanned since there is only one bucket for a single scan
@@ -685,7 +364,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,30 +378,15 @@
@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) {
- return mHwPnoDebouncer.startPnoScan(pnoSettings, mHwPnoDebouncerListener);
+ return mWifiNative.startPnoScan(pnoSettings);
}
private void stopHwPnoScan() {
- mHwPnoDebouncer.stopPnoScan();
- }
-
- private void pauseHwPnoScan() {
- mHwPnoDebouncer.forceStopPnoScan();
- }
-
- private boolean restartHwPnoScan(WifiNative.PnoSettings pnoSettings) {
- mHwPnoDebouncer.forceStopPnoScan();
- return mHwPnoDebouncer.startPnoScan(pnoSettings, mHwPnoDebouncerListener);
+ mWifiNative.stopPnoScan();
}
/**
@@ -734,24 +398,27 @@
return (!isConnectedPno & mHwPnoScanSupported);
}
- private boolean isHwPnoScanRequired() {
- if (mPnoSettings == null) return false;
- return isHwPnoScanRequired(mPnoSettings.isConnected);
- }
-
@Override
public boolean setHwPnoList(WifiNative.PnoSettings settings,
WifiNative.PnoEventHandler eventHandler) {
synchronized (mSettingsLock) {
- if (mPnoSettings != null) {
+ if (mLastPnoScanSettings != null) {
Log.w(TAG, "Already running a PNO scan");
return false;
}
- mPnoEventHandler = eventHandler;
- mPnoSettings = settings;
+ if (!isHwPnoScanRequired(settings.isConnected)) {
+ return false;
+ }
- // For wificond based PNO, we start the scan immediately when we set pno list.
- processPendingScans();
+ if (startHwPnoScan(settings)) {
+ mLastPnoScanSettings = new LastPnoScanSettings(
+ mClock.getElapsedSinceBootMillis(),
+ settings.networkList, eventHandler);
+
+ } else {
+ Log.e(TAG, "Failed to start PNO scan");
+ reportPnoScanFailure();
+ }
return true;
}
}
@@ -759,12 +426,11 @@
@Override
public boolean resetHwPnoList() {
synchronized (mSettingsLock) {
- if (mPnoSettings == null) {
+ if (mLastPnoScanSettings == null) {
Log.w(TAG, "No PNO scan running");
return false;
}
- mPnoEventHandler = null;
- mPnoSettings = null;
+ mLastPnoScanSettings = null;
// For wificond based PNO, we stop the scan immediately when we reset pno list.
stopHwPnoScan();
return true;
@@ -778,11 +444,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:");
@@ -817,260 +478,36 @@
}
private static class LastScanSettings {
- public long startTime;
-
- LastScanSettings(long startTime) {
- 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;
- public ChannelCollection singleScanFreqs;
- public WifiNative.ScanEventHandler singleScanEventHandler;
-
- public void setSingleScan(boolean reportSingleScanFullResults,
+ LastScanSettings(long startTime,
+ boolean reportSingleScanFullResults,
ChannelCollection singleScanFreqs,
WifiNative.ScanEventHandler singleScanEventHandler) {
- singleScanActive = true;
+ this.startTime = startTime;
this.reportSingleScanFullResults = reportSingleScanFullResults;
this.singleScanFreqs = singleScanFreqs;
this.singleScanEventHandler = singleScanEventHandler;
}
- public boolean hwPnoScanActive = false;
- public WifiNative.PnoNetwork[] pnoNetworkList;
- public WifiNative.PnoEventHandler pnoScanEventHandler;
+ public long startTime;
+ public boolean reportSingleScanFullResults;
+ public ChannelCollection singleScanFreqs;
+ public WifiNative.ScanEventHandler singleScanEventHandler;
- public void setHwPnoScan(
+ }
+
+ private static class LastPnoScanSettings {
+ LastPnoScanSettings(long startTime,
WifiNative.PnoNetwork[] pnoNetworkList,
WifiNative.PnoEventHandler pnoScanEventHandler) {
- hwPnoScanActive = true;
+ this.startTime = startTime;
this.pnoNetworkList = pnoNetworkList;
this.pnoScanEventHandler = pnoScanEventHandler;
}
+
+ public long startTime;
+ public WifiNative.PnoNetwork[] pnoNetworkList;
+ public WifiNative.PnoEventHandler pnoScanEventHandler;
+
}
-
- 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.
- * Note: This is not thread safe!
- */
- public static class HwPnoDebouncer {
- public static final String PNO_DEBOUNCER_ALARM_TAG = TAG + "Pno Monitor";
- private static final int MINIMUM_PNO_GAP_MS = 5 * 1000;
-
- private final WifiNative mWifiNative;
- private final AlarmManager mAlarmManager;
- private final Handler mEventHandler;
- private final Clock mClock;
- private long mLastPnoChangeTimeStamp = -1L;
- private boolean mExpectedPnoState = false;
- private boolean mCurrentPnoState = false;;
- private boolean mWaitForTimer = false;
- private Listener mListener;
- private WifiNative.PnoSettings mPnoSettings;
-
- /**
- * Interface used to indicate PNO scan notifications.
- */
- public interface Listener {
- /**
- * Used to indicate a delayed PNO scan request failure.
- */
- void onPnoScanFailed();
- }
-
- public HwPnoDebouncer(WifiNative wifiNative, AlarmManager alarmManager,
- Handler eventHandler, Clock clock) {
- mWifiNative = wifiNative;
- mAlarmManager = alarmManager;
- mEventHandler = eventHandler;
- mClock = clock;
- }
-
- /**
- * Enable PNO state in wificond
- */
- private boolean startPnoScanInternal() {
- if (mCurrentPnoState) {
- if (DBG) Log.d(TAG, "PNO state is already enable");
- return true;
- }
- if (mPnoSettings == null) {
- Log.e(TAG, "PNO state change to enable failed, no available Pno settings");
- return false;
- }
- mLastPnoChangeTimeStamp = mClock.getElapsedSinceBootMillis();
- Log.d(TAG, "Remove all networks from supplicant before starting PNO scan");
- mWifiNative.removeAllNetworks();
- if (mWifiNative.startPnoScan(mPnoSettings)) {
- Log.d(TAG, "Changed PNO state from " + mCurrentPnoState + " to enable");
- mCurrentPnoState = true;
- return true;
- } else {
- Log.e(TAG, "PNO state change to enable failed");
- mCurrentPnoState = false;
- }
- return false;
- }
-
- /**
- * Disable PNO state in wificond
- */
- private boolean stopPnoScanInternal() {
- if (!mCurrentPnoState) {
- if (DBG) Log.d(TAG, "PNO state is already disable");
- return true;
- }
- mLastPnoChangeTimeStamp = mClock.getElapsedSinceBootMillis();
- if (mWifiNative.stopPnoScan()) {
- Log.d(TAG, "Changed PNO state from " + mCurrentPnoState + " to disable");
- mCurrentPnoState = false;
- return true;
- } else {
- Log.e(TAG, "PNO state change to disable failed");
- mCurrentPnoState = false;
- }
- return false;
- }
-
- private final AlarmManager.OnAlarmListener mAlarmListener =
- new AlarmManager.OnAlarmListener() {
- public void onAlarm() {
- if (DBG) Log.d(TAG, "PNO timer expired, expected state " + mExpectedPnoState);
- if (mExpectedPnoState) {
- if (!startPnoScanInternal()) {
- if (mListener != null) {
- mListener.onPnoScanFailed();
- }
- }
- } else {
- stopPnoScanInternal();
- }
- mWaitForTimer = false;
- }
- };
-
- /**
- * Enable/Disable PNO state. This method will debounce PNO scan requests.
- * @param enable boolean indicating whether PNO is being enabled or disabled.
- */
- private boolean setPnoState(boolean enable) {
- boolean isSuccess = true;
- mExpectedPnoState = enable;
- if (!mWaitForTimer) {
- long timeDifference = mClock.getElapsedSinceBootMillis() - mLastPnoChangeTimeStamp;
- if (timeDifference >= MINIMUM_PNO_GAP_MS) {
- if (enable) {
- isSuccess = startPnoScanInternal();
- } else {
- isSuccess = stopPnoScanInternal();
- }
- } else {
- long alarmTimeout = MINIMUM_PNO_GAP_MS - timeDifference;
- Log.d(TAG, "Start PNO timer with delay " + alarmTimeout);
- mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
- mClock.getElapsedSinceBootMillis() + alarmTimeout,
- PNO_DEBOUNCER_ALARM_TAG,
- mAlarmListener, mEventHandler);
- mWaitForTimer = true;
- }
- }
- return isSuccess;
- }
-
- /**
- * Start PNO scan
- */
- public boolean startPnoScan(WifiNative.PnoSettings pnoSettings, Listener listener) {
- if (DBG) Log.d(TAG, "Starting PNO scan");
- mListener = listener;
- mPnoSettings = pnoSettings;
- if (!setPnoState(true)) {
- mListener = null;
- return false;
- }
- return true;
- }
-
- /**
- * Stop PNO scan
- */
- public void stopPnoScan() {
- if (DBG) Log.d(TAG, "Stopping PNO scan");
- setPnoState(false);
- mListener = null;
- }
-
- /**
- * Force stop PNO scanning. This method will bypass the debounce logic and stop PNO
- * scan immediately.
- */
- public void forceStopPnoScan() {
- if (DBG) Log.d(TAG, "Force stopping Pno scan");
- // Cancel the debounce timer and stop PNO scan.
- if (mWaitForTimer) {
- mAlarmManager.cancel(mAlarmListener);
- mWaitForTimer = false;
- }
- stopPnoScanInternal();
- }
- }
}
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..4ae7d13 100644
--- a/service/java/com/android/server/wifi/util/WifiPermissionsUtil.java
+++ b/service/java/com/android/server/wifi/util/WifiPermissionsUtil.java
@@ -17,23 +17,15 @@
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 +44,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 +56,6 @@
mSettingsStore = settingsStore;
mLog = wifiInjector.makeLog(TAG);
mNetworkScoreManager = networkScoreManager;
- mFrameworkFacade = wifiInjector.getFrameworkFacade();
}
/**
@@ -101,16 +91,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 +156,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 +180,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.
*/
@@ -329,24 +201,19 @@
* current user.
*/
private boolean isCurrentProfile(int uid) {
- final long token = Binder.clearCallingIdentity();
- try {
- int currentUser = mWifiPermissionsWrapper.getCurrentUser();
- int callingUserId = mWifiPermissionsWrapper.getCallingUserId(uid);
- if (callingUserId == currentUser) {
- return true;
- } else {
- List<UserInfo> userProfiles = mUserManager.getProfiles(currentUser);
- for (UserInfo user : userProfiles) {
- if (user.id == callingUserId) {
- return true;
- }
+ int currentUser = mWifiPermissionsWrapper.getCurrentUser();
+ int callingUserId = mWifiPermissionsWrapper.getCallingUserId(uid);
+ if (callingUserId == currentUser) {
+ return true;
+ } else {
+ List<UserInfo> userProfiles = mUserManager.getProfiles(currentUser);
+ for (UserInfo user : userProfiles) {
+ if (user.id == callingUserId) {
+ return true;
}
}
- return false;
- } finally {
- Binder.restoreCallingIdentity(token);
}
+ return false;
}
/**
diff --git a/service/java/com/android/server/wifi/util/WifiPermissionsWrapper.java b/service/java/com/android/server/wifi/util/WifiPermissionsWrapper.java
index 6fde01e..84aacdf 100644
--- a/service/java/com/android/server/wifi/util/WifiPermissionsWrapper.java
+++ b/service/java/com/android/server/wifi/util/WifiPermissionsWrapper.java
@@ -108,4 +108,16 @@
return AppGlobals.getPackageManager().checkUidPermission(
Manifest.permission.CHANGE_WIFI_STATE, uid);
}
+
+ /**
+ * Determines if the caller has local mac address permission.
+ *
+ * @param uid to check the permission for
+ * @return int representation of success or denied
+ * @throws RemoteException
+ */
+ public int getLocalMacAddressPermission(int uid) throws RemoteException {
+ return AppGlobals.getPackageManager().checkUidPermission(
+ Manifest.permission.LOCAL_MAC_ADDRESS, uid);
+ }
}
diff --git a/tests/wifitests/Android.mk b/tests/wifitests/Android.mk
index 1e64ddb..19a5efb 100644
--- a/tests/wifitests/Android.mk
+++ b/tests/wifitests/Android.mk
@@ -59,7 +59,7 @@
# since neither is declared a static java library.
LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-test \
- mockito-target-minus-junit4 \
+ mockito-target-inline-minus-junit4 \
frameworks-base-testutils \
services \
wifi-service \
@@ -68,7 +68,9 @@
android.test.runner \
wifi-service \
services \
- android.hidl.manager-V1.0-java
+ android.hidl.manager-V1.0-java \
+ android.test.base \
+ android.test.mock
# These must be explicitly included because they are not normally accessible
# from apps.
@@ -105,8 +107,10 @@
libwifi-system \
libui \
libunwind \
+ libunwindstack \
libutils \
libvndksupport \
+ libdexmakerjvmtiagent \
ifdef WPA_SUPPLICANT_VERSION
LOCAL_JNI_SHARED_LIBRARIES += libwpa_client
diff --git a/tests/wifitests/AndroidManifest.xml b/tests/wifitests/AndroidManifest.xml
index dcb61c7..31eaac9 100644
--- a/tests/wifitests/AndroidManifest.xml
+++ b/tests/wifitests/AndroidManifest.xml
@@ -19,7 +19,9 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.server.wifi.test">
- <application>
+ <application
+ android:debuggable="true"
+ android:largeHeap="true">
<uses-library android:name="android.test.runner" />
<activity android:label="WifiTestDummyLabel"
android:name="WifiTestDummyName">
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/coverage.sh b/tests/wifitests/coverage.sh
index 3ed71ad..b10ceaf 100755
--- a/tests/wifitests/coverage.sh
+++ b/tests/wifitests/coverage.sh
@@ -40,6 +40,7 @@
-f build/core/main.mk \
MODULES-IN-frameworks-opt-net-wifi-tests \
MODULES-IN-system-core \
+ MODULES-IN-external-jacoco \
FrameworksWifiTests
adb root
diff --git a/tests/wifitests/runtests.sh b/tests/wifitests/runtests.sh
index 7a34bf7..d5b631c 100755
--- a/tests/wifitests/runtests.sh
+++ b/tests/wifitests/runtests.sh
@@ -41,5 +41,4 @@
adb install -r -g "$OUT/data/app/FrameworksWifiTests/FrameworksWifiTests.apk"
adb shell am instrument -w "$@" \
- -e notAnnotation com.android.server.wifi.DisabledForUpdateToAnyMatcher \
'com.android.server.wifi.test/com.android.server.wifi.CustomTestRunner'
diff --git a/tests/wifitests/src/com/android/server/wifi/DisabledForUpdateToAnyMatcher.java b/tests/wifitests/src/com/android/server/wifi/DisabledForUpdateToAnyMatcher.java
deleted file mode 100644
index 6f1df47..0000000
--- a/tests/wifitests/src/com/android/server/wifi/DisabledForUpdateToAnyMatcher.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * 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 java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-@Retention(RetentionPolicy.RUNTIME)
-public @interface DisabledForUpdateToAnyMatcher {
-}
diff --git a/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java b/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java
index 7a25e17..3e3ce42 100644
--- a/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java
@@ -51,10 +51,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 +85,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 +100,10 @@
private WifiStatus mStatusFail;
private class HalDeviceManagerSpy extends HalDeviceManager {
+ HalDeviceManagerSpy() {
+ super(mClock);
+ }
+
@Override
protected IWifi getWifiServiceMockable() {
return mWifiMock;
@@ -111,6 +120,7 @@
MockitoAnnotations.initMocks(this);
mTestLooper = new TestLooper();
+ mHandler = new Handler(mTestLooper.getLooper());
// initialize dummy status objects
mStatusOk = getStatus(WifiStatusCode.SUCCESS);
@@ -141,6 +151,10 @@
dumpDut("after: ");
}
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Chip Independent Tests
+ //////////////////////////////////////////////////////////////////////////////////////
+
/**
* Test basic startup flow:
* - IServiceManager registrations
@@ -196,9 +210,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,654 +288,97 @@
}
/**
- * 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);
+ InOrder availInOrder = inOrder(staAvailListener, nanAvailListener);
+
// 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
+ "wlan0", // ifaceName
+ TestChipV1.STA_CHIP_MODE_ID, // finalChipMode
null, // tearDownList
staDestroyedListener, // destroyedListener
staAvailListener // availableListener
);
+ availInOrder.verify(staAvailListener).onAvailabilityChanged(false);
// 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
+ "wlan0", // ifaceName
+ TestChipV1.STA_CHIP_MODE_ID, // finalChipMode
null, // tearDownList
nanDestroyedListener, // destroyedListener
nanAvailListener // availableListener
);
+ availInOrder.verify(nanAvailListener).onAvailabilityChanged(false);
// fiddle with the "chip" by removing the STA
- chipMock.interfaceNames.get(IfaceType.STA).remove("sta0");
+ chipMock.interfaceNames.get(IfaceType.STA).remove("wlan0");
// now try to request another NAN
- nanIface = mDut.createNanIface(nanDestroyedListener, mTestLooper.getLooper());
+ IWifiIface nanIface2 = mDut.createNanIface(nanDestroyedListener, mHandler);
+ collector.checkThat("NAN can't be created", nanIface2, IsNull.nullValue());
+
mDut.registerInterfaceAvailableForRequestListener(IfaceType.NAN, nanAvailListener,
- mTestLooper.getLooper());
- collector.checkThat("NAN can't be created", nanIface, IsNull.nullValue());
+ mHandler);
+ mTestLooper.dispatchAll();
+
+ // extra (apparently duplicate) call since everything was cleaned-up once a cache mismatch
+ // was detected - so this is a call on a new registration
+ availInOrder.verify(nanAvailListener).onAvailabilityChanged(false);
// 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);
@@ -936,8 +393,8 @@
false, // chipModeValid
-1000, // chipModeId (only used if chipModeValid is true)
IfaceType.STA, // ifaceTypeToCreate
- "sta0", // ifaceName
- BaselineChip.STA_CHIP_MODE_ID, // finalChipMode
+ "wlan0", // ifaceName
+ TestChipV1.STA_CHIP_MODE_ID, // finalChipMode
null, // tearDownList
null, // destroyedListener
null // availableListener
@@ -946,72 +403,24 @@
// act: register the same listener twice
mDut.registerInterfaceAvailableForRequestListener(IfaceType.STA, staAvailListener,
- mTestLooper.getLooper());
+ mHandler);
mDut.registerInterfaceAvailableForRequestListener(IfaceType.STA, staAvailListener,
- mTestLooper.getLooper());
+ mHandler);
mTestLooper.dispatchAll();
+ verify(staAvailListener).onAvailabilityChanged(false);
+
// remove STA interface -> should trigger callbacks
mDut.removeIface(staIface);
mTestLooper.dispatchAll();
// verify: only a single trigger
- verify(staAvailListener).onAvailableForRequest();
+ verify(staAvailListener).onAvailabilityChanged(true);
verifyNoMoreInteractions(staAvailListener);
}
/**
- * 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 +434,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 +455,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 +473,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 +514,1160 @@
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, "wlan0",
+ TestChipV1.STA_CHIP_MODE_ID, false);
+ }
+
+ /**
+ * Validate creation of AP interface from blank start-up. The remove interface.
+ */
+ @Test
+ public void testCreateApInterfaceNoInitModeTestChipV1() throws Exception {
+ runCreateSingleXxxInterfaceNoInitMode(new TestChipV1(), IfaceType.AP, "wlan0",
+ TestChipV1.AP_CHIP_MODE_ID, false);
+ }
+
+ /**
+ * 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, false);
+ }
+
+ /**
+ * Validate creation of NAN interface from blank start-up. The remove interface.
+ */
+ @Test
+ public void testCreateNanInterfaceNoInitModeTestChipV1() throws Exception {
+ runCreateSingleXxxInterfaceNoInitMode(new TestChipV1(), IfaceType.NAN, "wlan0",
+ TestChipV1.STA_CHIP_MODE_ID, false);
+ }
+
+ // 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, "wlan0",
+ TestChipV2.CHIP_MODE_ID, true);
+ }
+
+ /**
+ * Validate creation of AP interface from blank start-up. The remove interface.
+ */
+ @Test
+ public void testCreateApInterfaceNoInitModeTestChipV2() throws Exception {
+ runCreateSingleXxxInterfaceNoInitMode(new TestChipV2(), IfaceType.AP, "wlan0",
+ TestChipV2.CHIP_MODE_ID, false);
+ }
+
+ /**
+ * 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, false);
+ }
+
+ /**
+ * Validate creation of NAN interface from blank start-up. The remove interface.
+ */
+ @Test
+ public void testCreateNanInterfaceNoInitModeTestChipV2() throws Exception {
+ runCreateSingleXxxInterfaceNoInitMode(new TestChipV2(), IfaceType.NAN, "wlan0",
+ TestChipV2.CHIP_MODE_ID, false);
+ }
+
+ // TestChipV3
+
+ /**
+ * Validate creation of STA interface from blank start-up. The remove interface.
+ */
+ @Test
+ public void testCreateStaInterfaceNoInitModeTestChipV3() 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 TestChipV3(), IfaceType.STA, "wlan0",
+ TestChipV3.CHIP_MODE_ID, true);
+ }
+
+ /**
+ * Validate creation of AP interface from blank start-up. The remove interface.
+ */
+ @Test
+ public void testCreateApInterfaceNoInitModeTestChipV3() throws Exception {
+ runCreateSingleXxxInterfaceNoInitMode(new TestChipV3(), IfaceType.AP, "wlan0",
+ TestChipV3.CHIP_MODE_ID, false);
+ }
+
+ /**
+ * Validate creation of P2P interface from blank start-up. The remove interface.
+ */
+ @Test
+ public void testCreateP2pInterfaceNoInitModeTestChipV3() throws Exception {
+ runCreateSingleXxxInterfaceNoInitMode(new TestChipV3(), IfaceType.P2P, "p2p0",
+ TestChipV3.CHIP_MODE_ID, false);
+ }
+
+ /**
+ * Validate creation of NAN interface from blank start-up. The remove interface.
+ */
+ @Test
+ public void testCreateNanInterfaceNoInitModeTestChipV3() throws Exception {
+ runCreateSingleXxxInterfaceNoInitMode(new TestChipV3(), IfaceType.NAN, "wlan0",
+ TestChipV3.CHIP_MODE_ID, false);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // 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 = "wlan0";
+
+ 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());
+
+ verify(iafrl).onAvailabilityChanged(false);
+
+ // 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).onAvailabilityChanged(true);
+ mInOrder.verify(apIafrl).onAvailabilityChanged(true);
+
+ // 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(staIafrl).onAvailabilityChanged(false);
+
+ // 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(apIafrl).onAvailabilityChanged(false);
+ mInOrder.verify(staIafrl).onAvailabilityChanged(true);
+
+ // 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 = "wlan0";
+
+ 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());
+
+ verify(iafrl).onAvailabilityChanged(false);
+
+ // 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 inOrderAvail = inOrder(staAvailListener, apAvailListener, p2pAvailListener,
+ 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();
+
+ inOrderAvail.verify(staAvailListener).onAvailabilityChanged(true);
+ inOrderAvail.verify(apAvailListener).onAvailabilityChanged(true);
+ inOrderAvail.verify(p2pAvailListener).onAvailabilityChanged(true);
+ inOrderAvail.verify(nanAvailListener).onAvailabilityChanged(true);
+
+ // Request STA
+ IWifiIface staIface = validateInterfaceSequence(chipMock,
+ false, // chipModeValid
+ -1000, // chipModeId (only used if chipModeValid is true)
+ IfaceType.STA, // ifaceTypeToCreate
+ "wlan0", // ifaceName
+ TestChipV1.STA_CHIP_MODE_ID, // finalChipMode
+ null, // tearDownList
+ staDestroyedListener, // destroyedListener
+ null // availableListener
+ );
+ collector.checkThat("allocated STA interface", staIface, IsNull.notNullValue());
+
+ inOrderAvail.verify(staAvailListener).onAvailabilityChanged(false);
+
+ // 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());
+
+ inOrderAvail.verify(p2pAvailListener).onAvailabilityChanged(false);
+ inOrderAvail.verify(nanAvailListener).onAvailabilityChanged(false);
+
+ // Request AP
+ IWifiIface apIface = validateInterfaceSequence(chipMock,
+ true, // chipModeValid
+ TestChipV1.STA_CHIP_MODE_ID, // chipModeId
+ IfaceType.AP, // ifaceTypeToCreate
+ "wlan0", // 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());
+
+ inOrderAvail.verify(apAvailListener).onAvailabilityChanged(false);
+ inOrderAvail.verify(staAvailListener).onAvailabilityChanged(true);
+
+ // 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
+ "wlan0", // 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());
+
+ inOrderAvail.verify(apAvailListener).onAvailabilityChanged(true);
+ inOrderAvail.verify(staAvailListener).onAvailabilityChanged(false);
+ inOrderAvail.verify(p2pAvailListener).onAvailabilityChanged(true);
+ inOrderAvail.verify(nanAvailListener).onAvailabilityChanged(true);
+
+ 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
+ );
+
+ inOrderAvail.verify(p2pAvailListener).onAvailabilityChanged(false);
+ inOrderAvail.verify(nanAvailListener).onAvailabilityChanged(false);
+
+ // 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();
+
+ inOrderAvail.verify(p2pAvailListener).onAvailabilityChanged(true);
+ inOrderAvail.verify(nanAvailListener).onAvailabilityChanged(true);
+ 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
+ "wlan0", // ifaceName
+ TestChipV1.STA_CHIP_MODE_ID, // finalChipMode
+ null, // tearDownList
+ nanDestroyedListener, // destroyedListener
+ nanAvailListener // availableListener
+ );
+ collector.checkThat("allocated NAN interface", nanIface, IsNull.notNullValue());
+
+ inOrderAvail.verify(nanAvailListener).onAvailabilityChanged(false);
+
+ 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(), 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
+ "wlan0", // ifaceName
+ TestChipV1.STA_CHIP_MODE_ID, // finalChipMode
+ null, // tearDownList
+ staDestroyedListener1, // destroyedListener
+ staAvailListener1 // availableListener
+ );
+ collector.checkThat("STA created", staIface1, IsNull.notNullValue());
+
+ verify(staAvailListener1).onAvailabilityChanged(false);
+
+ // 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 inOrderAvail = inOrder(staAvailListener, apAvailListener, p2pAvailListener,
+ 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();
+
+ inOrderAvail.verify(staAvailListener).onAvailabilityChanged(true);
+ inOrderAvail.verify(apAvailListener).onAvailabilityChanged(true);
+ inOrderAvail.verify(p2pAvailListener).onAvailabilityChanged(true);
+ inOrderAvail.verify(nanAvailListener).onAvailabilityChanged(true);
+
+ // create STA
+ when(mClock.getUptimeSinceBootMillis()).thenReturn(15L);
+ IWifiIface staIface = validateInterfaceSequence(chipMock,
+ false, // chipModeValid
+ -1000, // chipModeId (only used if chipModeValid is true)
+ IfaceType.STA, // ifaceTypeToCreate
+ "wlan0", // ifaceName
+ TestChipV2.CHIP_MODE_ID, // finalChipMode
+ null, // tearDownList
+ staDestroyedListener, // destroyedListener
+ null // availableListener (already registered)
+ );
+ collector.checkThat("STA interface wasn't created", staIface, IsNull.notNullValue());
+
+ // 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());
+
+ inOrderAvail.verify(p2pAvailListener).onAvailabilityChanged(false);
+ inOrderAvail.verify(nanAvailListener).onAvailabilityChanged(false);
+
+ // 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
+ "wlan1", // ifaceName
+ TestChipV2.CHIP_MODE_ID, // finalChipMode
+ null, // tearDownList
+ apDestroyedListener, // destroyedListener
+ null // availableListener (already registered)
+ );
+ collector.checkThat("AP interface wasn't created", apIface, IsNull.notNullValue());
+
+ inOrderAvail.verify(apAvailListener).onAvailabilityChanged(false);
+ inOrderAvail.verify(staAvailListener).onAvailabilityChanged(false);
+
+ // 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();
+
+ inOrderAvail.verify(apAvailListener).onAvailabilityChanged(true);
+ inOrderAvail.verify(staAvailListener).onAvailabilityChanged(true);
+ verify(chipMock.chip).removeApIface("wlan1");
+ 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
+ "wlan1", // 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());
+
+ inOrderAvail.verify(staAvailListener).onAvailabilityChanged(false);
+
+ // 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
+ "wlan1", // 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());
+
+ inOrderAvail.verify(apAvailListener).onAvailabilityChanged(false);
+
+ // tear down P2P
+ mDut.removeIface(p2pIface);
+ mTestLooper.dispatchAll();
+
+ inOrderAvail.verify(p2pAvailListener).onAvailabilityChanged(true);
+ inOrderAvail.verify(nanAvailListener).onAvailabilityChanged(true);
+ 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
+ "wlan0", // ifaceName
+ TestChipV2.CHIP_MODE_ID, // finalChipMode
+ null, // tearDownList
+ nanDestroyedListener, // destroyedListener
+ null // availableListener (already registered)
+ );
+ collector.checkThat("NAN interface wasn't created", nanIface, IsNull.notNullValue());
+
+ inOrderAvail.verify(nanAvailListener).onAvailabilityChanged(false);
+
+ 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(), 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);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // TestChipV3 Specific Tests
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Validate a flow sequence for test chip 3:
+ * - create STA
+ * - create P2P
+ * - request NAN: failure
+ * - create AP: should tear down P2P first
+ * - create STA: will get refused
+ * - create AP: will get refused
+ * - request P2P: failure
+ * - tear down AP
+ * - create STA
+ * - create STA: will get refused
+ * - create NAN: should tear down last created STA
+ * - create STA: will get refused
+ */
+ @Test
+ public void testInterfaceCreationFlowTestChipV3() throws Exception {
+ TestChipV3 chipMock = new TestChipV3();
+ 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 inOrderAvail = inOrder(staAvailListener, apAvailListener, p2pAvailListener,
+ 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();
+
+ inOrderAvail.verify(staAvailListener).onAvailabilityChanged(true);
+ inOrderAvail.verify(apAvailListener).onAvailabilityChanged(true);
+ inOrderAvail.verify(p2pAvailListener).onAvailabilityChanged(true);
+ inOrderAvail.verify(nanAvailListener).onAvailabilityChanged(true);
+
+ // create STA
+ when(mClock.getUptimeSinceBootMillis()).thenReturn(15L);
+ IWifiIface staIface = validateInterfaceSequence(chipMock,
+ false, // chipModeValid
+ -1000, // chipModeId (only used if chipModeValid is true)
+ IfaceType.STA, // ifaceTypeToCreate
+ "wlan0", // ifaceName
+ TestChipV3.CHIP_MODE_ID, // finalChipMode
+ null, // tearDownList
+ staDestroyedListener, // destroyedListener
+ null // availableListener (already registered)
+ );
+ collector.checkThat("STA interface wasn't created", staIface, IsNull.notNullValue());
+
+ // create P2P
+ IWifiIface p2pIface = validateInterfaceSequence(chipMock,
+ true, // chipModeValid
+ TestChipV3.CHIP_MODE_ID, // chipModeId
+ IfaceType.P2P, // ifaceTypeToCreate
+ "p2p0", // ifaceName
+ TestChipV3.CHIP_MODE_ID, // finalChipMode
+ null, // tearDownList
+ p2pDestroyedListener, // destroyedListener
+ null // availableListener (already registered)
+ );
+ collector.checkThat("P2P interface wasn't created", p2pIface, IsNull.notNullValue());
+
+ inOrderAvail.verify(staAvailListener).onAvailabilityChanged(false);
+ inOrderAvail.verify(p2pAvailListener).onAvailabilityChanged(false);
+ inOrderAvail.verify(nanAvailListener).onAvailabilityChanged(false);
+
+ // request NAN: should fail
+ IWifiIface nanIface = mDut.createNanIface(null, null);
+ collector.checkThat("NAN should not be created", nanIface, IsNull.nullValue());
+
+ // create AP: will destroy P2P
+ IWifiIface apIface = validateInterfaceSequence(chipMock,
+ true, // chipModeValid
+ TestChipV3.CHIP_MODE_ID, // chipModeId
+ IfaceType.AP, // ifaceTypeToCreate
+ "wlan1", // ifaceName
+ TestChipV3.CHIP_MODE_ID, // finalChipMode
+ null, // tearDownList
+ apDestroyedListener, // destroyedListener
+ null, // availableListener (already registered)
+ new InterfaceDestroyedListenerWithIfaceName("p2p0", p2pDestroyedListener)
+ );
+ collector.checkThat("AP interface wasn't created", apIface, IsNull.notNullValue());
+ verify(chipMock.chip).removeP2pIface("p2p0");
+
+ inOrderAvail.verify(apAvailListener).onAvailabilityChanged(false);
+
+ // 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());
+
+ // request P2P: should fail
+ p2pIface = mDut.createP2pIface(null, null);
+ collector.checkThat("P2P should not be created", p2pIface, IsNull.nullValue());
+
+ // tear down AP
+ mDut.removeIface(apIface);
+ mTestLooper.dispatchAll();
+
+ inOrderAvail.verify(apAvailListener).onAvailabilityChanged(true);
+ inOrderAvail.verify(staAvailListener).onAvailabilityChanged(true);
+ inOrderAvail.verify(p2pAvailListener).onAvailabilityChanged(true);
+ inOrderAvail.verify(nanAvailListener).onAvailabilityChanged(true);
+ verify(chipMock.chip).removeApIface("wlan1");
+ verify(apDestroyedListener).onDestroyed(getName(apIface));
+
+ // create STA2: using a later clock
+ when(mClock.getUptimeSinceBootMillis()).thenReturn(20L);
+ staIface2 = validateInterfaceSequence(chipMock,
+ true, // chipModeValid
+ TestChipV3.CHIP_MODE_ID, // chipModeId
+ IfaceType.STA, // ifaceTypeToCreate
+ "wlan1", // ifaceName
+ TestChipV3.CHIP_MODE_ID, // finalChipMode
+ null, // tearDownList
+ staDestroyedListener2, // destroyedListener
+ null // availableListener (already registered)
+ );
+ collector.checkThat("STA 2 interface wasn't created", staIface2, IsNull.notNullValue());
+
+ inOrderAvail.verify(staAvailListener).onAvailabilityChanged(false);
+
+ // request STA3: should fail
+ IWifiIface staIface3 = mDut.createStaIface(null, null);
+ collector.checkThat("STA3 should not be created", staIface3, IsNull.nullValue());
+
+ // create NAN: should destroy the last created STA (STA2)
+ nanIface = validateInterfaceSequence(chipMock,
+ true, // chipModeValid
+ TestChipV3.CHIP_MODE_ID, // chipModeId
+ IfaceType.NAN, // ifaceTypeToCreate
+ "wlan0", // ifaceName
+ TestChipV3.CHIP_MODE_ID, // finalChipMode
+ null, // tearDownList
+ nanDestroyedListener, // destroyedListener
+ null, // availableListener (already registered)
+ new InterfaceDestroyedListenerWithIfaceName(
+ getName(staIface2), staDestroyedListener2)
+ );
+ collector.checkThat("NAN interface wasn't created", nanIface, IsNull.notNullValue());
+
+ inOrderAvail.verify(nanAvailListener).onAvailabilityChanged(false);
+ verify(chipMock.chip).removeStaIface("wlan1");
+ verify(staDestroyedListener2).onDestroyed(getName(staIface2));
+
+ // request STA2: should fail
+ staIface2 = mDut.createStaIface(null, null);
+ collector.checkThat("STA2 should not be created", staIface2, IsNull.nullValue());
+
+ 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 testP2pAndNanInteractionsTestChipV3() throws Exception {
+ runP2pAndNanExclusiveInteractionsTestChip(new TestChipV3(), TestChipV3.CHIP_MODE_ID);
+ }
+
+ /**
+ * Validate that the getSupportedIfaceTypes API works when requesting for all chips.
+ */
+ @Test
+ public void testGetSupportedIfaceTypesAllTestChipV3() throws Exception {
+ TestChipV3 chipMock = new TestChipV3();
+ 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 testGetSupportedIfaceTypesOneChipTestChipV3() throws Exception {
+ TestChipV3 chipMock = new TestChipV3();
+ 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 +1711,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 +1727,189 @@
}
}
+ private void runCreateSingleXxxInterfaceNoInitMode(ChipMockBase chipMock, int ifaceTypeToCreate,
+ String ifaceName, int finalChipMode, boolean multipleIfaceSupport) 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);
+
+ InOrder availInOrder = inOrder(iafrl);
+
+ 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());
+ availInOrder.verify(iafrl).onAvailabilityChanged(multipleIfaceSupport);
+
+ // 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);
+ if (!multipleIfaceSupport) {
+ availInOrder.verify(iafrl).onAvailabilityChanged(true);
+ }
+
+ 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,
+ 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);
+
+ InOrder availInOrder = inOrder(staAvailListener, nanAvailListener);
+
+ // Request STA
+ IWifiIface staIface = validateInterfaceSequence(chipMock,
+ false, // chipModeValid
+ -1000, // chipModeId (only used if chipModeValid is true)
+ IfaceType.STA, // ifaceTypeToCreate
+ "wlan0", // ifaceName
+ onlyChipMode, // finalChipMode
+ null, // tearDownList
+ staDestroyedListener, // destroyedListener
+ staAvailListener // availableListener
+ );
+ availInOrder.verify(staAvailListener).onAvailabilityChanged(
+ chipMock.chipMockId == CHIP_MOCK_V2 || chipMock.chipMockId == CHIP_MOCK_V3);
+
+ // Request NAN
+ IWifiIface nanIface = validateInterfaceSequence(chipMock,
+ true, // chipModeValid
+ onlyChipMode, // chipModeId
+ IfaceType.NAN, // ifaceTypeToCreate
+ "wlan0", // ifaceName
+ onlyChipMode, // finalChipMode
+ null, // tearDownList
+ nanDestroyedListener, // destroyedListener
+ nanAvailListener // availableListener
+ );
+ if (chipMock.chipMockId == CHIP_MOCK_V3) {
+ availInOrder.verify(staAvailListener).onAvailabilityChanged(false);
+ }
+ availInOrder.verify(nanAvailListener).onAvailabilityChanged(false);
+
+ // Request P2P
+ IWifiIface p2pIface = validateInterfaceSequence(chipMock,
+ true, // chipModeValid
+ onlyChipMode, // chipModeId
+ IfaceType.P2P, // ifaceTypeToCreate
+ "p2p0", // ifaceName
+ onlyChipMode, // finalChipMode
+ new IWifiIface[]{nanIface}, // tearDownList
+ p2pDestroyedListener, // destroyedListener
+ null, // 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));
+ if (chipMock.chipMockId == CHIP_MOCK_V3) {
+ availInOrder.verify(staAvailListener).onAvailabilityChanged(true);
+ }
+ availInOrder.verify(nanAvailListener).onAvailabilityChanged(true);
+
+ // Request NAN: expect success now
+ nanIface = validateInterfaceSequence(chipMock,
+ true, // chipModeValid
+ onlyChipMode, // chipModeId
+ IfaceType.NAN, // ifaceTypeToCreate
+ "wlan0", // ifaceName
+ onlyChipMode, // finalChipMode
+ null, // tearDownList
+ nanDestroyedListener, // destroyedListener
+ nanAvailListener // availableListener
+ );
+ if (chipMock.chipMockId == CHIP_MOCK_V3) {
+ availInOrder.verify(staAvailListener).onAvailabilityChanged(false);
+ }
+ availInOrder.verify(nanAvailListener).onAvailabilityChanged(false);
+
+ 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 +1929,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 +1940,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 +1951,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 +1962,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 +2020,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 +2047,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;
@@ -1540,7 +2302,13 @@
// chip configuration
+ private static final int CHIP_MOCK_V1 = 0;
+ private static final int CHIP_MOCK_V2 = 1;
+ private static final int CHIP_MOCK_V3 = 2;
+
private class ChipMockBase {
+ public int chipMockId;
+
public IWifiChip chip;
public int chipId;
public boolean chipModeValid = false;
@@ -1598,16 +2366,18 @@
}
}
- // 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;
void initialize() throws Exception {
super.initialize();
+ chipMockId = CHIP_MOCK_V1;
+
// chip Id configuration
ArrayList<Integer> chipIds;
chipId = 10;
@@ -1659,4 +2429,132 @@
.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();
+
+ chipMockId = CHIP_MOCK_V2;
+
+ // 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));
+ }
+ }
+
+ // test chip configuration V3:
+ // mode:
+ // STA + (STA || AP)
+ // STA + (NAN || P2P)
+ private class TestChipV3 extends ChipMockBase {
+ // only mode (different number from any in other TestChips so can catch test errors)
+ static final int CHIP_MODE_ID = 7;
+
+ void initialize() throws Exception {
+ super.initialize();
+
+ chipMockId = CHIP_MOCK_V3;
+
+ // chip Id configuration
+ ArrayList<Integer> chipIds;
+ chipId = 15;
+ 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(15),
+ 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}, 1xSTA + 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);
+
+ cm.availableCombinations.add(cic);
+
+ 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.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..b53de95
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/PasspointProvisioningTestUtil.java
@@ -0,0 +1,69 @@
+/*
+ * 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 Uri INVALID_SERVER_URI = Uri.parse("abcd");
+ 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);
+ }
+ }
+
+ /**
+ * Construct a {@link android.net.wifi.hotspot2.OsuProvider} with invalid server URL
+ * @return the constructed {@link android.net.wifi.hotspot2.OsuProvider}
+ */
+ public static OsuProvider generateInvalidServerUrlOsuProvider() {
+ return new OsuProvider(TEST_SSID, TEST_FRIENDLY_NAME, TEST_SERVICE_DESCRIPTION,
+ INVALID_SERVER_URI, null, 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..93db347 100644
--- a/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java
@@ -16,25 +16,43 @@
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.app.test.TestAlarmManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.database.ContentObserver;
import android.net.InterfaceConfiguration;
+import android.net.Uri;
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.RemoteException;
+import android.os.UserHandle;
import android.os.test.TestLooper;
+import android.provider.Settings;
import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Pair;
+import com.android.internal.R;
+import com.android.internal.util.WakeupMessage;
import com.android.server.net.BaseNetworkObserver;
import org.junit.Before;
@@ -44,9 +62,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 +75,37 @@
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();
- TestLooper mLooper;
+ private ContentObserver mContentObserver;
+ private TestLooper mLooper;
+ private TestAlarmManager mAlarmManager;
+
+ @Mock Context mContext;
+ @Mock Resources mResources;
@Mock WifiNative mWifiNative;
@Mock SoftApManager.Listener mListener;
@Mock InterfaceConfiguration mInterfaceConfiguration;
- @Mock IBinder mApInterfaceBinder;
+ @Mock FrameworkFacade mFrameworkFacade;
@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 +115,18 @@
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);
+
+ when(mFrameworkFacade.getIntegerSetting(
+ mContext, Settings.Global.SOFT_AP_TIMEOUT_ENABLED, 1)).thenReturn(1);
+ mAlarmManager = new TestAlarmManager();
+ when(mContext.getSystemService(Context.ALARM_SERVICE))
+ .thenReturn(mAlarmManager.getAlarmManager());
+ when(mContext.getResources()).thenReturn(mResources);
+ when(mResources.getInteger(R.integer.config_wifi_framework_soft_ap_timeout_delay))
+ .thenReturn(600000);
}
private WifiConfiguration createDefaultApConfig() {
@@ -102,18 +135,16 @@
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(),
+ mFrameworkFacade,
mWifiNative,
TEST_COUNTRY_CODE,
mListener,
- mApInterface,
mNmService,
mWifiApConfigStore,
config,
@@ -125,7 +156,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 +167,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 +182,818 @@
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(mWifiNative.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
+ when(mApInterface.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
+ when(mWifiNative.setupForSoftApMode(eq(TEST_INTERFACE_NAME)))
+ .thenReturn(Pair.create(WifiNative.SETUP_SUCCESS, mApInterface));
+ when(mApInterface.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
+
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(),
+ mFrameworkFacade,
mWifiNative,
TEST_COUNTRY_CODE,
mListener,
- mApInterface,
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());
+ }
+
+ /**
+ * Test that failure to create the SoftApInterface increments the corresponding metrics and
+ * proper state updates are sent out.
+ */
+ @Test
+ public void testSetupForSoftApModeHalFailureIncrementsMetrics() throws Exception {
+ when(mWifiNative.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
+ when(mWifiNative.setupForSoftApMode(TEST_INTERFACE_NAME))
+ .thenReturn(Pair.create(WifiNative.SETUP_FAILURE_HAL, null));
+
+ SoftApModeConfiguration config = new SoftApModeConfiguration(
+ WifiManager.IFACE_IP_MODE_TETHERED, new WifiConfiguration());
+
+ when(mWifiApConfigStore.getApConfiguration()).thenReturn(null);
+ SoftApModeConfiguration nullApConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null);
+ SoftApManager newSoftApManager = new SoftApManager(mContext,
+ mLooper.getLooper(),
+ mFrameworkFacade,
+ mWifiNative,
+ TEST_COUNTRY_CODE,
+ mListener,
+ mNmService,
+ mWifiApConfigStore,
+ 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).sendStickyBroadcastAsUser(intentCaptor.capture(),
+ eq(UserHandle.ALL));
+
+ checkApStateChangedBroadcast(intentCaptor.getValue(), WIFI_AP_STATE_FAILED,
+ WIFI_AP_STATE_DISABLED, WifiManager.SAP_START_FAILURE_GENERAL, null,
+ nullApConfig.getTargetMode());
+
+ verify(mWifiMetrics).incrementNumWifiOnFailureDueToHal();
+ }
+
+ /**
+ * Test that failure to create the SoftApInterface due to a wificond error increments
+ * the corresponding metrics and proper state updates are sent out.
+ */
+ @Test
+ public void testSetupForSoftApModeWificondFailureIncrementsMetrics() throws Exception {
+ when(mWifiNative.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
+ when(mWifiNative.setupForSoftApMode(TEST_INTERFACE_NAME))
+ .thenReturn(Pair.create(WifiNative.SETUP_FAILURE_WIFICOND, null));
+
+ SoftApModeConfiguration config = new SoftApModeConfiguration(
+ WifiManager.IFACE_IP_MODE_TETHERED, new WifiConfiguration());
+
+ when(mWifiApConfigStore.getApConfiguration()).thenReturn(null);
+ SoftApModeConfiguration nullApConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null);
+ SoftApManager newSoftApManager = new SoftApManager(mContext,
+ mLooper.getLooper(),
+ mFrameworkFacade,
+ mWifiNative,
+ TEST_COUNTRY_CODE,
+ mListener,
+ mNmService,
+ mWifiApConfigStore,
+ 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).sendStickyBroadcastAsUser(intentCaptor.capture(),
+ eq(UserHandle.ALL));
+
+ checkApStateChangedBroadcast(intentCaptor.getValue(), WIFI_AP_STATE_FAILED,
+ WIFI_AP_STATE_DISABLED, WifiManager.SAP_START_FAILURE_GENERAL, null,
+ nullApConfig.getTargetMode());
+
+ verify(mWifiMetrics).incrementNumWifiOnFailureDueToWificond();
+ }
+
+ /**
+ * Test that failure to retrieve the SoftApInterface increments the corresponding metrics
+ * and proper state updates are sent out.
+ */
+ @Test
+ public void testSetupForSoftApModeNullApInterfaceFailureIncrementsMetrics() throws Exception {
+ when(mWifiNative.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
+ when(mWifiNative.setupForSoftApMode(eq(TEST_INTERFACE_NAME)))
+ .thenReturn(Pair.create(WifiNative.SETUP_SUCCESS, null));
+
+ SoftApModeConfiguration config = new SoftApModeConfiguration(
+ WifiManager.IFACE_IP_MODE_TETHERED, new WifiConfiguration());
+
+ when(mWifiApConfigStore.getApConfiguration()).thenReturn(null);
+ SoftApModeConfiguration nullApConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null);
+ SoftApManager newSoftApManager = new SoftApManager(mContext,
+ mLooper.getLooper(),
+ mFrameworkFacade,
+ mWifiNative,
+ TEST_COUNTRY_CODE,
+ mListener,
+ mNmService,
+ mWifiApConfigStore,
+ 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).sendStickyBroadcastAsUser(intentCaptor.capture(),
+ eq(UserHandle.ALL));
+
+ checkApStateChangedBroadcast(intentCaptor.getValue(), WIFI_AP_STATE_FAILED,
+ WIFI_AP_STATE_DISABLED, WifiManager.SAP_START_FAILURE_GENERAL, null,
+ nullApConfig.getTargetMode());
+
+ verify(mWifiMetrics).incrementSoftApStartResult(false,
+ WifiManager.SAP_START_FAILURE_GENERAL);
+ }
+
+ /**
+ * Test that an empty SoftApInterface name is detected as a failure and increments the
+ * corresponding metrics and proper state updates are sent out.
+ */
+ @Test
+ public void testSetupForSoftApModeEmptyInterfaceNameFailureIncrementsMetrics()
+ throws Exception {
+ when(mWifiNative.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
+ when(mApInterface.getInterfaceName()).thenReturn("");
+ when(mWifiNative.setupForSoftApMode(eq(TEST_INTERFACE_NAME)))
+ .thenReturn(Pair.create(WifiNative.SETUP_SUCCESS, mApInterface));
+
+ SoftApModeConfiguration config = new SoftApModeConfiguration(
+ WifiManager.IFACE_IP_MODE_TETHERED, new WifiConfiguration());
+
+ when(mWifiApConfigStore.getApConfiguration()).thenReturn(null);
+ SoftApModeConfiguration nullApConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null);
+ SoftApManager newSoftApManager = new SoftApManager(mContext,
+ mLooper.getLooper(),
+ mFrameworkFacade,
+ mWifiNative,
+ TEST_COUNTRY_CODE,
+ mListener,
+ mNmService,
+ mWifiApConfigStore,
+ 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).sendStickyBroadcastAsUser(intentCaptor.capture(),
+ eq(UserHandle.ALL));
+
+ checkApStateChangedBroadcast(intentCaptor.getValue(), WIFI_AP_STATE_FAILED,
+ WIFI_AP_STATE_DISABLED, WifiManager.SAP_START_FAILURE_GENERAL, "",
+ nullApConfig.getTargetMode());
+
+ verify(mWifiMetrics).incrementSoftApStartResult(false,
+ WifiManager.SAP_START_FAILURE_GENERAL);
+ }
+
+ /**
+ * Test that catching a RemoteException when retrieving the SoftApInterface name
+ * is detected as a failure and increments the corresponding metrics and proper
+ * state updates are sent out.
+ */
+ @Test
+ public void testSetupForSoftApModeInterfaceNameRemoteExceptionFailureIncrementsMetrics()
+ throws Exception {
+ when(mWifiNative.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
+ doThrow(new RemoteException()).when(mApInterface).getInterfaceName();
+ when(mWifiNative.setupForSoftApMode(eq(TEST_INTERFACE_NAME)))
+ .thenReturn(Pair.create(WifiNative.SETUP_SUCCESS, mApInterface));
+
+ SoftApModeConfiguration config = new SoftApModeConfiguration(
+ WifiManager.IFACE_IP_MODE_TETHERED, new WifiConfiguration());
+
+ when(mWifiApConfigStore.getApConfiguration()).thenReturn(null);
+ SoftApModeConfiguration nullApConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null);
+ SoftApManager newSoftApManager = new SoftApManager(mContext,
+ mLooper.getLooper(),
+ mFrameworkFacade,
+ mWifiNative,
+ TEST_COUNTRY_CODE,
+ mListener,
+ mNmService,
+ mWifiApConfigStore,
+ 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).sendStickyBroadcastAsUser(intentCaptor.capture(),
+ eq(UserHandle.ALL));
+
+ checkApStateChangedBroadcast(intentCaptor.getValue(), WIFI_AP_STATE_FAILED,
+ WIFI_AP_STATE_DISABLED, WifiManager.SAP_START_FAILURE_GENERAL, null,
+ nullApConfig.getTargetMode());
+
+ verify(mWifiMetrics).incrementSoftApStartResult(false,
+ WifiManager.SAP_START_FAILURE_GENERAL);
+ }
+
+
+ /**
+ * Tests that the generic error is propagated and properly reported when starting softap and we
+ * cannot register a wificond death handler.
+ */
+ @Test
+ public void startSoftApFailRegisterWificondDeathHandlerGeneralError() 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.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
+ when(mApInterface.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
+ when(mWifiNative.setupForSoftApMode(eq(TEST_INTERFACE_NAME)))
+ .thenReturn(Pair.create(WifiNative.SETUP_SUCCESS, mApInterface));
+
+ when(mWifiNative.registerWificondDeathHandler(any())).thenReturn(false);
+
+ SoftApManager newSoftApManager = new SoftApManager(mContext,
+ mLooper.getLooper(),
+ mFrameworkFacade,
+ mWifiNative,
+ null,
+ mListener,
+ 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());
+ verify(mWifiMetrics).incrementSoftApStartResult(false,
+ WifiManager.SAP_START_FAILURE_GENERAL);
+ }
+
+ /**
+ * Tests that the generic error is propagated and properly reported when starting softap and we
+ * catch a RemoteException when attempting to register a NetworkObserver.
+ */
+ @Test
+ public void startSoftApFailNetworkObserverRemoteExceptionGeneralError() 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.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
+ when(mApInterface.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
+ when(mWifiNative.setupForSoftApMode(eq(TEST_INTERFACE_NAME)))
+ .thenReturn(Pair.create(WifiNative.SETUP_SUCCESS, mApInterface));
+
+ doThrow(new RemoteException()).when(mNmService).registerObserver(any());
+
+ SoftApManager newSoftApManager = new SoftApManager(mContext,
+ mLooper.getLooper(),
+ mFrameworkFacade,
+ mWifiNative,
+ null,
+ mListener,
+ 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());
+ // we do once on enter of idle, and another after the failure
+ verify(mWifiNative, times(2)).deregisterWificondDeathHandler();
+ verify(mNmService).unregisterObserver(any());
+ verify(mWifiMetrics).incrementSoftApStartResult(false,
+ WifiManager.SAP_START_FAILURE_GENERAL);
+ }
+
+ /**
+ * 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.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
+ when(mApInterface.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
+ when(mWifiNative.setupForSoftApMode(eq(TEST_INTERFACE_NAME)))
+ .thenReturn(Pair.create(WifiNative.SETUP_SUCCESS, mApInterface));
+
+ when(mWifiNative.isHalStarted()).thenReturn(true);
+
+ SoftApManager newSoftApManager = new SoftApManager(mContext,
+ mLooper.getLooper(),
+ mFrameworkFacade,
+ mWifiNative,
+ null,
+ mListener,
+ 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);
+
+ when(mWifiNative.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
+ when(mApInterface.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
+ when(mWifiNative.setupForSoftApMode(eq(TEST_INTERFACE_NAME)))
+ .thenReturn(Pair.create(WifiNative.SETUP_SUCCESS, mApInterface));
+
+
+ SoftApManager newSoftApManager = new SoftApManager(mContext,
+ mLooper.getLooper(),
+ mFrameworkFacade,
+ mWifiNative,
+ TEST_COUNTRY_CODE,
+ mListener,
+ 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);
+ when(mWifiNative.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
+ when(mWifiNative.setupForSoftApMode(eq(TEST_INTERFACE_NAME)))
+ .thenReturn(Pair.create(WifiNative.SETUP_SUCCESS, mApInterface));
+
+ SoftApModeConfiguration softApModeConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, mDefaultApConfig);
+
+ SoftApManager newSoftApManager = new SoftApManager(mContext,
+ mLooper.getLooper(),
+ mFrameworkFacade,
+ mWifiNative,
+ TEST_COUNTRY_CODE,
+ mListener,
+ 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();
+ verify(mWifiMetrics).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();
+ verify(mWifiMetrics, times(1)).addSoftApNumAssociatedStationsChangedEvent(
+ TEST_NUM_CONNECTED_CLIENTS, apConfig.getTargetMode());
+ }
+
+ @Test
+ public void schedulesTimeoutTimerOnStart() throws Exception {
+ SoftApModeConfiguration apConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null);
+ startSoftApAndVerifyEnabled(apConfig);
+
+ // Verify timer is scheduled
+ verify(mAlarmManager.getAlarmManager()).setExact(anyInt(), anyLong(),
+ eq(mSoftApManager.SOFT_AP_SEND_MESSAGE_TIMEOUT_TAG), any(), any());
+ }
+
+ @Test
+ public void cancelsTimeoutTimerOnStop() throws Exception {
+ SoftApModeConfiguration apConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null);
+ startSoftApAndVerifyEnabled(apConfig);
+ mSoftApManager.stop();
+ mLooper.dispatchAll();
+
+ // Verify timer is canceled
+ verify(mAlarmManager.getAlarmManager()).cancel(any(WakeupMessage.class));
+ }
+
+ @Test
+ public void cancelsTimeoutTimerOnNewClientsConnect() throws Exception {
+ SoftApModeConfiguration apConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null);
+ startSoftApAndVerifyEnabled(apConfig);
+ mSoftApListenerCaptor.getValue().onNumAssociatedStationsChanged(
+ TEST_NUM_CONNECTED_CLIENTS);
+ mLooper.dispatchAll();
+
+ // Verify timer is canceled
+ verify(mAlarmManager.getAlarmManager()).cancel(any(WakeupMessage.class));
+ }
+
+ @Test
+ public void schedulesTimeoutTimerWhenAllClientsDisconnect() throws Exception {
+ SoftApModeConfiguration apConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null);
+ startSoftApAndVerifyEnabled(apConfig);
+
+ mSoftApListenerCaptor.getValue().onNumAssociatedStationsChanged(
+ TEST_NUM_CONNECTED_CLIENTS);
+ mLooper.dispatchAll();
+ // Verify timer is canceled at this point
+ verify(mAlarmManager.getAlarmManager()).cancel(any(WakeupMessage.class));
+
+ mSoftApListenerCaptor.getValue().onNumAssociatedStationsChanged(0);
+ mLooper.dispatchAll();
+ // Verify timer is scheduled again
+ verify(mAlarmManager.getAlarmManager(), times(2)).setExact(anyInt(), anyLong(),
+ eq(mSoftApManager.SOFT_AP_SEND_MESSAGE_TIMEOUT_TAG), any(), any());
+ }
+
+ @Test
+ public void stopsSoftApOnTimeoutMessage() throws Exception {
+ SoftApModeConfiguration apConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null);
+ startSoftApAndVerifyEnabled(apConfig);
+
+ mAlarmManager.dispatch(mSoftApManager.SOFT_AP_SEND_MESSAGE_TIMEOUT_TAG);
+ mLooper.dispatchAll();
+
+ verify(mWifiNative).stopSoftAp();
+ }
+
+ @Test
+ public void cancelsTimeoutTimerOnTimeoutToggleChangeWhenNoClients() throws Exception {
+ SoftApModeConfiguration apConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null);
+ startSoftApAndVerifyEnabled(apConfig);
+
+ when(mFrameworkFacade.getIntegerSetting(
+ mContext, Settings.Global.SOFT_AP_TIMEOUT_ENABLED, 1)).thenReturn(0);
+ mContentObserver.onChange(false);
+ mLooper.dispatchAll();
+
+ // Verify timer is canceled
+ verify(mAlarmManager.getAlarmManager()).cancel(any(WakeupMessage.class));
+ }
+
+ @Test
+ public void schedulesTimeoutTimerOnTimeoutToggleChangeWhenNoClients() throws Exception {
+ // start with timeout toggle disabled
+ when(mFrameworkFacade.getIntegerSetting(
+ mContext, Settings.Global.SOFT_AP_TIMEOUT_ENABLED, 1)).thenReturn(0);
+ SoftApModeConfiguration apConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null);
+ startSoftApAndVerifyEnabled(apConfig);
+
+ when(mFrameworkFacade.getIntegerSetting(
+ mContext, Settings.Global.SOFT_AP_TIMEOUT_ENABLED, 1)).thenReturn(1);
+ mContentObserver.onChange(false);
+ mLooper.dispatchAll();
+
+ // Verify timer is scheduled
+ verify(mAlarmManager.getAlarmManager()).setExact(anyInt(), anyLong(),
+ eq(mSoftApManager.SOFT_AP_SEND_MESSAGE_TIMEOUT_TAG), any(), any());
+ }
+
+ @Test
+ public void doesNotScheduleTimeoutTimerOnStartWhenTimeoutIsDisabled() throws Exception {
+ // start with timeout toggle disabled
+ when(mFrameworkFacade.getIntegerSetting(
+ mContext, Settings.Global.SOFT_AP_TIMEOUT_ENABLED, 1)).thenReturn(0);
+ SoftApModeConfiguration apConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null);
+ startSoftApAndVerifyEnabled(apConfig);
+
+ // Verify timer is not scheduled
+ verify(mAlarmManager.getAlarmManager(), never()).setExact(anyInt(), anyLong(),
+ eq(mSoftApManager.SOFT_AP_SEND_MESSAGE_TIMEOUT_TAG), any(), any());
+ }
+
+ @Test
+ public void doesNotScheduleTimeoutTimerWhenAllClientsDisconnectButTimeoutIsDisabled()
+ throws Exception {
+ // start with timeout toggle disabled
+ when(mFrameworkFacade.getIntegerSetting(
+ mContext, Settings.Global.SOFT_AP_TIMEOUT_ENABLED, 1)).thenReturn(0);
+ SoftApModeConfiguration apConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null);
+ startSoftApAndVerifyEnabled(apConfig);
+ // add some clients
+ mSoftApListenerCaptor.getValue().onNumAssociatedStationsChanged(
+ TEST_NUM_CONNECTED_CLIENTS);
+ mLooper.dispatchAll();
+ // remove all clients
+ mSoftApListenerCaptor.getValue().onNumAssociatedStationsChanged(0);
+ mLooper.dispatchAll();
+ // Verify timer is not scheduled
+ verify(mAlarmManager.getAlarmManager(), never()).setExact(anyInt(), anyLong(),
+ eq(mSoftApManager.SOFT_AP_SEND_MESSAGE_TIMEOUT_TAG), any(), any());
+ }
+
+ @Test
+ public void unregistersSettingsObserverOnStop() throws Exception {
+ SoftApModeConfiguration apConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null);
+ startSoftApAndVerifyEnabled(apConfig);
+ mSoftApManager.stop();
+ mLooper.dispatchAll();
+
+ verify(mFrameworkFacade).unregisterContentObserver(eq(mContext), eq(mContentObserver));
}
/** 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<ContentObserver> observerCaptor = ArgumentCaptor.forClass(
+ ContentObserver.class);
+ ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+
+ when(mWifiNative.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
+ when(mApInterface.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME);
+ when(mWifiNative.setupForSoftApMode(eq(TEST_INTERFACE_NAME)))
+ .thenReturn(Pair.create(WifiNative.SETUP_SUCCESS, mApInterface));
+
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());
+ verify(mWifiMetrics).addSoftApUpChangedEvent(true, softApConfig.mTargetMode);
+ verify(mFrameworkFacade).registerContentObserver(eq(mContext), any(Uri.class), eq(true),
+ observerCaptor.capture());
+ mContentObserver = observerCaptor.getValue();
}
/** Verifies that soft AP was not disabled. */
@@ -250,4 +1001,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..11a0a47 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,22 +85,26 @@
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;
private static final String HS20_URL = "http://blahblah";
- @Mock IServiceManager mServiceManagerMock;
- @Mock ISupplicant mISupplicantMock;
- @Mock ISupplicantIface mISupplicantIfaceMock;
- @Mock ISupplicantStaIface mISupplicantStaIfaceMock;
- @Mock Context mContext;
- @Mock WifiMonitor mWifiMonitor;
- @Mock SupplicantStaNetworkHal mSupplicantStaNetworkMock;
+ private @Mock IServiceManager mServiceManagerMock;
+ private @Mock ISupplicant mISupplicantMock;
+ private android.hardware.wifi.supplicant.V1_1.ISupplicant mISupplicantMockV1_1;
+ private @Mock ISupplicantIface mISupplicantIfaceMock;
+ private @Mock ISupplicantStaIface mISupplicantStaIfaceMock;
+ private @Mock Context mContext;
+ private @Mock WifiMonitor mWifiMonitor;
+ private @Mock SupplicantStaNetworkHal mSupplicantStaNetworkMock;
+ private @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;
@@ -136,12 +135,19 @@
}
@Override
+ protected android.hardware.wifi.supplicant.V1_1.ISupplicant getSupplicantMockableV1_1()
+ throws RemoteException {
+ return mISupplicantMockV1_1;
+ }
+
+ @Override
protected ISupplicantStaIface getStaIfaceMockable(ISupplicantIface iface) {
return mISupplicantStaIfaceMock;
}
@Override
protected SupplicantStaNetworkHal getStaNetworkMockable(
+ @NonNull String ifaceName,
ISupplicantStaNetwork iSupplicantStaNetwork) {
return mSupplicantStaNetworkMock;
}
@@ -152,11 +158,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),
@@ -216,6 +224,109 @@
}
/**
+ * Sunny day scenario for SupplicantStaIfaceHal initialization
+ * Asserts successful initialization
+ */
+ @Test
+ public void testInitialize_successV1_1() throws Exception {
+ mISupplicantMockV1_1 = mock(android.hardware.wifi.supplicant.V1_1.ISupplicant.class);
+ executeAndValidateInitializationSequenceV1_1(false, false);
+ }
+
+ /**
+ * Tests the initialization flow, with a RemoteException occurring when 'getInterface' is called
+ * Ensures initialization fails.
+ */
+ @Test
+ public void testInitialize_remoteExceptionFailureV1_1() throws Exception {
+ mISupplicantMockV1_1 = mock(android.hardware.wifi.supplicant.V1_1.ISupplicant.class);
+ executeAndValidateInitializationSequenceV1_1(true, false);
+ }
+
+ /**
+ * Tests the initialization flow, with a null interface being returned by getInterface.
+ * Ensures initialization fails.
+ */
+ @Test
+ public void testInitialize_nullInterfaceFailureV1_1() throws Exception {
+ mISupplicantMockV1_1 = mock(android.hardware.wifi.supplicant.V1_1.ISupplicant.class);
+ executeAndValidateInitializationSequenceV1_1(false, true);
+ }
+
+ /**
+ * 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.
+ */
+ @Test
+ public void testTeardownInterface() throws Exception {
+ testInitialize_success();
+ assertTrue(mDut.teardownIface(WLAN0_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();
+ }
+
+ /**
+ * Sunny day scenario for SupplicantStaIfaceHal interface teardown.
+ */
+ @Test
+ public void testTeardownInterfaceV1_1() throws Exception {
+ testInitialize_successV1_1();
+
+ when(mISupplicantMockV1_1.removeInterface(any())).thenReturn(mStatusSuccess);
+ assertTrue(mDut.teardownIface(WLAN0_IFACE_NAME));
+ verify(mISupplicantMockV1_1).removeInterface(any());
+
+ // Ensure that the cancel wps operation is failed because there are no interfaces setup.
+ assertFalse(mDut.cancelWps(WLAN0_IFACE_NAME));
+ verify(mISupplicantStaIfaceMock, never()).cancelWps();
+ }
+
+ /**
+ * 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));
+ }
+
+ /**
+ * 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 +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(3, configs.size());
assertEquals(3, extras.size());
@@ -316,7 +427,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 +466,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 +491,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 +522,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 +555,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 +579,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 +593,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 +636,7 @@
}).when(mISupplicantStaIfaceMock).addNetwork(
any(ISupplicantStaIface.addNetworkCallback.class));
- assertFalse(mDut.connectToNetwork(createTestWifiConfiguration()));
+ assertFalse(mDut.connectToNetwork(WLAN0_IFACE_NAME, createTestWifiConfiguration()));
}
/**
@@ -517,7 +650,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 +668,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 +684,7 @@
when(mSupplicantStaNetworkMock.select()).thenReturn(false);
- assertFalse(mDut.connectToNetwork(createTestWifiConfiguration()));
+ assertFalse(mDut.connectToNetwork(WLAN0_IFACE_NAME, createTestWifiConfiguration()));
}
/**
@@ -561,7 +694,7 @@
public void testRoamToSameNetwork() throws Exception {
executeAndValidateInitializationSequence();
executeAndValidateRoamSequence(true);
- assertTrue(mDut.connectToNetwork(createTestWifiConfiguration()));
+ assertTrue(mDut.connectToNetwork(WLAN0_IFACE_NAME, createTestWifiConfiguration()));
}
/**
@@ -586,7 +719,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 +741,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 +757,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 +786,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 +799,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 +816,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 +834,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 +852,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 +870,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 +888,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 +906,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 +928,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 +951,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 +979,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 +1002,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 +1026,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 +1067,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 +1087,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 +1108,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 +1126,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 +1161,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 +1176,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 +1188,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 +1215,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 +1228,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 +1242,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 +1269,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 +1282,7 @@
assertNotNull(mISupplicantStaIfaceCallback);
mISupplicantStaIfaceCallback.onWpsEventSuccess();
- verify(mWifiMonitor).broadcastWpsSuccessEvent(eq(WLAN_IFACE_NAME));
+ verify(mWifiMonitor).broadcastWpsSuccessEvent(eq(WLAN0_IFACE_NAME));
}
/**
@@ -1145,7 +1297,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 +1313,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 +1325,7 @@
assertNotNull(mISupplicantStaIfaceCallback);
mISupplicantStaIfaceCallback.onWpsEventPbcOverlap();
- verify(mWifiMonitor).broadcastWpsOverlapEvent(eq(WLAN_IFACE_NAME));
+ verify(mWifiMonitor).broadcastWpsOverlapEvent(eq(WLAN0_IFACE_NAME));
}
/**
@@ -1184,11 +1336,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 +1353,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 +1374,7 @@
mSupplicantStaIfaceDeathCaptor.getValue().serviceDied(5L);
assertFalse(mDut.isInitializationComplete());
- verify(mWifiMonitor).broadcastSupplicantDisconnectionEvent(eq(WLAN_IFACE_NAME));
+ verify(mWifiMonitor).broadcastSupplicantDisconnectionEvent(eq(WLAN0_IFACE_NAME));
}
/**
@@ -1268,17 +1424,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 +1449,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 +1478,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 +1555,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 +1568,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(
@@ -1421,6 +1579,76 @@
}
}
+ /**
+ * Calls.initialize(), mocking various call back answers and verifying flow, asserting for the
+ * expected result. Verifies if ISupplicantStaIface manager is initialized or reset.
+ * Each of the arguments will cause a different failure mode when set true.
+ */
+ private void executeAndValidateInitializationSequenceV1_1(boolean causeRemoteException,
+ boolean getNullInterface)
+ throws Exception {
+ boolean shouldSucceed = !causeRemoteException && !getNullInterface;
+ // Setup callback mock answers
+ if (causeRemoteException) {
+ doThrow(new RemoteException("Some error!!!"))
+ .when(mISupplicantMockV1_1).addInterface(any(ISupplicant.IfaceInfo.class),
+ any(android.hardware.wifi.supplicant.V1_1.ISupplicant
+ .addInterfaceCallback.class));
+ } else {
+ doAnswer(new GetAddInterfaceAnswer(getNullInterface))
+ .when(mISupplicantMockV1_1).addInterface(any(ISupplicant.IfaceInfo.class),
+ any(android.hardware.wifi.supplicant.V1_1.ISupplicant
+ .addInterfaceCallback.class));
+ }
+ /** Callback registeration */
+ doAnswer(new MockAnswerUtil.AnswerWithArguments() {
+ public SupplicantStatus answer(ISupplicantStaIfaceCallback cb)
+ throws RemoteException {
+ mISupplicantStaIfaceCallback = cb;
+ return mStatusSuccess;
+ }
+ }).when(mISupplicantStaIfaceMock)
+ .registerCallback(any(ISupplicantStaIfaceCallback.class));
+
+ mInOrder = inOrder(mServiceManagerMock, mISupplicantMock, mISupplicantMockV1_1,
+ mISupplicantStaIfaceMock, mWifiMonitor);
+ // Initialize SupplicantStaIfaceHal, should call serviceManager.registerForNotifications
+ assertTrue(mDut.initialize());
+ // verify: service manager initialization sequence
+ mInOrder.verify(mServiceManagerMock).linkToDeath(mServiceManagerDeathCaptor.capture(),
+ anyLong());
+ mInOrder.verify(mServiceManagerMock).registerForNotifications(
+ eq(ISupplicant.kInterfaceName), eq(""), mServiceNotificationCaptor.capture());
+ // act: cause the onRegistration(...) callback to execute
+ mServiceNotificationCaptor.getValue().onRegistration(ISupplicant.kInterfaceName, "", true);
+
+ assertTrue(mDut.isInitializationComplete());
+ assertTrue(mDut.setupIface(WLAN0_IFACE_NAME) == shouldSucceed);
+ mInOrder.verify(mISupplicantMock).linkToDeath(mSupplicantDeathCaptor.capture(),
+ anyLong());
+ // verify: addInterface is called
+ mInOrder.verify(mISupplicantMockV1_1)
+ .addInterface(any(ISupplicant.IfaceInfo.class),
+ any(android.hardware.wifi.supplicant.V1_1.ISupplicant
+ .addInterfaceCallback.class));
+ if (causeRemoteException) {
+ mInOrder.verify(mWifiMonitor).broadcastSupplicantDisconnectionEvent(
+ eq(WLAN0_IFACE_NAME));
+ }
+ if (!causeRemoteException && !getNullInterface) {
+ mInOrder.verify(mISupplicantStaIfaceMock).linkToDeath(
+ mSupplicantStaIfaceDeathCaptor.capture(), anyLong());
+ mInOrder.verify(mISupplicantStaIfaceMock)
+ .registerCallback(any(ISupplicantStaIfaceCallback.class));
+ }
+
+ // Ensure we don't try to use the listInterfaces method from 1.0 version.
+ verify(mISupplicantMock, never()).listInterfaces(
+ any(ISupplicant.listInterfacesCallback.class));
+ verify(mISupplicantMock, never()).getInterface(any(ISupplicant.IfaceInfo.class),
+ any(ISupplicant.getInterfaceCallback.class));
+ }
+
private SupplicantStatus createSupplicantStatus(int code) {
SupplicantStatus status = new SupplicantStatus();
status.code = code;
@@ -1465,6 +1693,24 @@
}
}
+ private class GetAddInterfaceAnswer extends MockAnswerUtil.AnswerWithArguments {
+ boolean mGetNullInterface;
+
+ GetAddInterfaceAnswer(boolean getNullInterface) {
+ mGetNullInterface = getNullInterface;
+ }
+
+ public void answer(ISupplicant.IfaceInfo iface,
+ android.hardware.wifi.supplicant.V1_1.ISupplicant
+ .addInterfaceCallback cb) {
+ if (mGetNullInterface) {
+ cb.onValues(mStatusSuccess, null);
+ } else {
+ cb.onValues(mStatusSuccess, mISupplicantIfaceMock);
+ }
+ }
+ }
+
/**
* Setup mocks for connect sequence.
*/
@@ -1529,7 +1775,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 +1812,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..6a72522
--- /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 = 2.1; // proportional to pps
+ mWifiInfo.txBadRate = .5;
+ mWifiInfo.rxSuccessRate = 2.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/WakeupConfigStoreDataTest.java b/tests/wifitests/src/com/android/server/wifi/WakeupConfigStoreDataTest.java
new file mode 100644
index 0000000..6db9cf5
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/WakeupConfigStoreDataTest.java
@@ -0,0 +1,164 @@
+/*
+ * 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.mockito.Mockito.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.util.Xml;
+
+import com.android.internal.util.FastXmlSerializer;
+
+import com.google.android.collect.Sets;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.Set;
+
+/**
+ * Unit tests for {@link WakeupConfigStoreData}.
+ */
+public class WakeupConfigStoreDataTest {
+
+ @Mock private WakeupConfigStoreData.DataSource<Boolean> mActiveDataSource;
+ @Mock private WakeupConfigStoreData.DataSource<Set<ScanResultMatchInfo>> mNetworkDataSource;
+
+ private WakeupConfigStoreData mWakeupConfigData;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mWakeupConfigData = new WakeupConfigStoreData(mActiveDataSource, mNetworkDataSource);
+ }
+
+ /**
+ * Helper function for serializing configuration data to a XML block.
+ *
+ * @param shared Flag indicating serializing shared or user configurations
+ * @return byte[] of the XML data
+ */
+ private byte[] serializeData(boolean shared) throws Exception {
+ final XmlSerializer out = new FastXmlSerializer();
+ final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ out.setOutput(outputStream, StandardCharsets.UTF_8.name());
+ mWakeupConfigData.serializeData(out, shared);
+ out.flush();
+ return outputStream.toByteArray();
+ }
+
+ /**
+ * Helper function for parsing configuration data from a XML block.
+ *
+ * @param data XML data to parse from
+ * @param shared Flag indicating parsing of shared or user configurations
+ */
+ private void deserializeData(byte[] data, boolean shared) throws Exception {
+ final XmlPullParser in = Xml.newPullParser();
+ final ByteArrayInputStream inputStream = new ByteArrayInputStream(data);
+ in.setInput(inputStream, StandardCharsets.UTF_8.name());
+ mWakeupConfigData.deserializeData(in, in.getDepth(), shared);
+ }
+
+ /**
+ * Verify that a XmlPullParserException will be thrown when attempting to serialize data
+ * to the share store.
+ */
+ @Test(expected = XmlPullParserException.class)
+ public void serializeShareDataThrowsException() throws Exception {
+ serializeData(true /* shared */);
+ }
+
+ /**
+ * Verify that a XmlPullParserException will be thrown when attempting to deserialize
+ * data from the share store.
+ */
+ @Test(expected = XmlPullParserException.class)
+ public void deserializeShareDataThrowsException() throws Exception {
+ deserializeData(new byte[0], true /* shared */);
+ }
+
+ /**
+ * Can correctly serialize and deserialize the empty set case.
+ */
+ @Test
+ public void deserializeSerializedData_emptySet() throws Exception {
+ Set<ScanResultMatchInfo> networks = Collections.emptySet();
+ boolean isActive = false;
+
+ when(mActiveDataSource.getData()).thenReturn(isActive);
+ when(mNetworkDataSource.getData()).thenReturn(networks);
+
+ byte[] bytes = serializeData(false /* shared */);
+ deserializeData(bytes, false /* shared */);
+
+ verify(mActiveDataSource).setData(eq(isActive));
+ verify(mNetworkDataSource).setData(eq(networks));
+ }
+
+ /**
+ * Can correctly serialize and deserialize a standard working case.
+ */
+ @Test
+ public void deserializeSerializedData() throws Exception {
+ ScanResultMatchInfo network1 = new ScanResultMatchInfo();
+ network1.networkSsid = "ssid 1";
+ network1.networkType = 0;
+
+ ScanResultMatchInfo network2 = new ScanResultMatchInfo();
+ network2.networkSsid = ",.23;4@, .#,%(,";
+ network2.networkType = 1;
+
+ ScanResultMatchInfo network3 = new ScanResultMatchInfo();
+ network3.networkSsid = "";
+ network3.networkType = 2;
+
+ Set<ScanResultMatchInfo> networks = Sets.newArraySet(network1, network2, network3);
+ boolean isActive = true;
+
+ when(mActiveDataSource.getData()).thenReturn(isActive);
+ when(mNetworkDataSource.getData()).thenReturn(networks);
+
+ byte[] bytes = serializeData(false /* shared */);
+ deserializeData(bytes, false /* shared */);
+
+ verify(mActiveDataSource).setData(eq(isActive));
+ verify(mNetworkDataSource).setData(eq(networks));
+ }
+
+ /**
+ * Verify that reset data wipes the data sources.
+ */
+ @Test
+ public void resetDataWipesDataSources() {
+ mWakeupConfigData.resetData(false /* shared */);
+
+ verify(mActiveDataSource).setData(false);
+ verify(mNetworkDataSource).setData(eq(Collections.emptySet()));
+ }
+}
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..afbd87a
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/WakeupControllerTest.java
@@ -0,0 +1,246 @@
+/*
+ * 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.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiScanner;
+import android.os.test.TestLooper;
+import android.provider.Settings;
+
+import com.android.server.wifi.util.ScanResultUtil;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+
+/**
+ * Unit tests for {@link WakeupController}.
+ */
+public class WakeupControllerTest {
+
+ @Mock private Context mContext;
+ @Mock private WakeupLock mWakeupLock;
+ @Mock private WifiConfigStore mWifiConfigStore;
+ @Mock private WifiInjector mWifiInjector;
+ @Mock private WifiScanner mWifiScanner;
+ @Mock private WifiConfigManager mWifiConfigManager;
+ @Mock private FrameworkFacade mFrameworkFacade;
+
+ private TestLooper mLooper;
+ private WakeupController mWakeupController;
+
+ /** Initialize objects before each test run. */
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ when(mWifiInjector.getWifiScanner()).thenReturn(mWifiScanner);
+ mLooper = new TestLooper();
+ }
+
+ /** Initializes the wakeupcontroller in the given `enabled` state. */
+ private void initializeWakeupController(boolean enabled) {
+ int settingsValue = enabled ? 1 : 0;
+ when(mFrameworkFacade.getIntegerSetting(mContext,
+ Settings.Global.WIFI_WAKEUP_ENABLED, 0)).thenReturn(settingsValue);
+ mWakeupController = new WakeupController(mContext,
+ mLooper.getLooper(),
+ mWakeupLock,
+ mWifiConfigManager,
+ mWifiConfigStore,
+ mWifiInjector,
+ mFrameworkFacade);
+ }
+
+ private ScanResult createOpenScanResult(String ssid) {
+ ScanResult scanResult = new ScanResult();
+ scanResult.SSID = ssid;
+ scanResult.capabilities = "";
+ return scanResult;
+ }
+
+ /**
+ * Verify WakeupController is enabled when the settings toggle is true.
+ */
+ @Test
+ public void verifyEnabledWhenToggledOn() {
+ initializeWakeupController(true /* enabled */);
+
+ assertTrue(mWakeupController.isEnabled());
+ }
+
+ /**
+ * Verify WakeupController is disabled when the settings toggle is false.
+ */
+ @Test
+ public void verifyDisabledWhenToggledOff() {
+ initializeWakeupController(false /* enabled */);
+
+ assertFalse(mWakeupController.isEnabled());
+ }
+
+ /**
+ * Verify WakeupController registers its store data with the WifiConfigStore on construction.
+ */
+ @Test
+ public void registersWakeupConfigStoreData() {
+ initializeWakeupController(true /* enabled */);
+ verify(mWifiConfigStore).registerStoreData(any(WakeupConfigStoreData.class));
+ }
+
+ /**
+ * Verify that dump calls also dump the state of the WakeupLock.
+ */
+ @Test
+ public void dumpIncludesWakeupLock() {
+ initializeWakeupController(true /* enabled */);
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ PrintWriter writer = new PrintWriter(stream);
+ mWakeupController.dump(null, writer, null);
+
+ verify(mWakeupLock).dump(null, writer, null);
+ }
+
+ /**
+ * Verify that start initializes the wakeup lock.
+ */
+ @Test
+ public void startInitializesWakeupLock() {
+ initializeWakeupController(true /* enabled */);
+ mWakeupController.start();
+ verify(mWakeupLock).initialize(any());
+ }
+
+ /**
+ * Verify that start does not initialize the wakeup lock when feature is disabled.
+ */
+ @Test
+ public void startDoesNotInitializeWakeupLockWhenDisabled() {
+ initializeWakeupController(false /* enabled */);
+ mWakeupController.start();
+ verify(mWakeupLock, never()).initialize(any());
+ }
+
+ /**
+ * Verify that start does not re-initialize the wakeup lock if the controller is already active.
+ */
+ @Test
+ public void startDoesNotInitializeWakeupLockIfAlreadyActive() {
+ initializeWakeupController(true /* enabled */);
+ InOrder inOrder = Mockito.inOrder(mWakeupLock);
+
+ mWakeupController.start();
+ inOrder.verify(mWakeupLock).initialize(any());
+
+ mWakeupController.stop();
+ mWakeupController.start();
+ inOrder.verify(mWakeupLock, never()).initialize(any());
+ }
+
+ /**
+ * Verify that start registers the scan listener on the wifi scanner.
+ */
+ @Test
+ public void startRegistersScanListener() {
+ initializeWakeupController(true /* enabled */);
+ mWakeupController.start();
+ verify(mWifiScanner).registerScanListener(any());
+ }
+
+ /**
+ * Verify that stop deregisters the scan listener from the wifi scanner.
+ */
+ @Test
+ public void stopDeresgistersScanListener() {
+ initializeWakeupController(true /* enabled */);
+ mWakeupController.start();
+ mWakeupController.stop();
+ verify(mWifiScanner).deregisterScanListener(any());
+ }
+
+ /**
+ * Verify that reset sets active to false.
+ *
+ * <p>This is accomplished by initiating another call to start and verifying that the wakeup
+ * lock is re-initialized.
+ */
+ @Test
+ public void resetSetsActiveToFalse() {
+ initializeWakeupController(true /* enabled */);
+ InOrder inOrder = Mockito.inOrder(mWakeupLock);
+
+ mWakeupController.start();
+ inOrder.verify(mWakeupLock).initialize(any());
+
+ mWakeupController.stop();
+ mWakeupController.reset();
+ mWakeupController.start();
+ inOrder.verify(mWakeupLock).initialize(any());
+ }
+
+ /**
+ * Verify that the wakeup lock is initialized with the intersection of ScanResults and saved
+ * networks.
+ */
+ @Test
+ public void startInitializesWakeupLockWithSavedScanResults() {
+ String ssid1 = "ssid 1";
+ String ssid2 = "ssid 2";
+ String quotedSsid = ScanResultUtil.createQuotedSSID(ssid1);
+
+ // saved configs
+ WifiConfiguration openNetwork = WifiConfigurationTestUtil.createOpenNetwork(quotedSsid);
+ openNetwork.getNetworkSelectionStatus().setHasEverConnected(true);
+ WifiConfiguration wepNetwork = WifiConfigurationTestUtil.createWepNetwork();
+ wepNetwork.getNetworkSelectionStatus().setHasEverConnected(true);
+ when(mWifiConfigManager.getSavedNetworks())
+ .thenReturn(Arrays.asList(openNetwork, wepNetwork));
+
+ // scan results from most recent scan
+ ScanResult savedScanResult = createOpenScanResult(ssid1);
+ ScanResult unsavedScanResult = createOpenScanResult(ssid2);
+ when(mWifiScanner.getSingleScanResults())
+ .thenReturn(Arrays.asList(savedScanResult, unsavedScanResult));
+
+ // intersection of most recent scan + saved configs
+ Collection<ScanResultMatchInfo> expectedMatchInfos =
+ Collections.singleton(ScanResultMatchInfo.fromScanResult(savedScanResult));
+
+ initializeWakeupController(true /* enabled */);
+ mWakeupController.start();
+ verify(mWakeupLock).initialize(eq(expectedMatchInfos));
+ }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/WakeupEvaluatorTest.java b/tests/wifitests/src/com/android/server/wifi/WakeupEvaluatorTest.java
new file mode 100644
index 0000000..d975018
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/WakeupEvaluatorTest.java
@@ -0,0 +1,156 @@
+/*
+ * 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.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.net.wifi.ScanResult;
+import android.util.ArraySet;
+
+import com.android.server.wifi.util.ScanResultUtil;
+
+import com.google.android.collect.Sets;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Collections;
+import java.util.Set;
+
+
+
+/**
+ * Unit tests for {@link WakeupEvaluator}.
+ */
+public class WakeupEvaluatorTest {
+
+ private static final String SAVED_SSID_1 = "saved ssid 1";
+ private static final String SAVED_SSID_2 = "saved ssid 2";
+ private static final String UNSAVED_SSID = "unsaved ssid";
+
+ private static final int FREQ_24 = 2402;
+ private static final int FREQ_5 = 5000;
+
+ private static final int THRESHOLD_24 = -10;
+ private static final int THRESHOLD_5 = -1;
+
+ private WakeupEvaluator mWakeupEvaluator;
+
+ private ScanResult makeScanResult(String ssid, int frequency, int level) {
+ ScanResult scanResult = new ScanResult();
+ scanResult.SSID = ssid;
+ scanResult.frequency = frequency;
+ scanResult.level = level;
+ scanResult.capabilities = "[]";
+
+ return scanResult;
+ }
+
+ private Set<ScanResultMatchInfo> getSavedNetworks() {
+ Set<ScanResultMatchInfo> networks = new ArraySet<>();
+ networks.add(ScanResultMatchInfo.fromWifiConfiguration(
+ WifiConfigurationTestUtil.createOpenNetwork(
+ ScanResultUtil.createQuotedSSID(SAVED_SSID_1))));
+ networks.add(ScanResultMatchInfo.fromWifiConfiguration(
+ WifiConfigurationTestUtil.createOpenNetwork(
+ ScanResultUtil.createQuotedSSID(SAVED_SSID_2))));
+ return networks;
+ }
+
+ @Before
+ public void setUp() {
+ mWakeupEvaluator = new WakeupEvaluator(THRESHOLD_24, THRESHOLD_5);
+ }
+
+ /**
+ * Verify that isBelowThreshold returns true for networks below the filter threshold.
+ */
+ @Test
+ public void isBelowThreshold_returnsTrueWhenRssiIsBelowThreshold() {
+ ScanResult scanResult24 = makeScanResult(SAVED_SSID_1, FREQ_24, THRESHOLD_24 - 1);
+ assertTrue(mWakeupEvaluator.isBelowThreshold(scanResult24));
+
+ ScanResult scanResult5 = makeScanResult(SAVED_SSID_1, FREQ_5, THRESHOLD_5 - 1);
+ assertTrue(mWakeupEvaluator.isBelowThreshold(scanResult5));
+ }
+
+ /**
+ * Verify that isBelowThreshold returns false for networks above the filter threshold.
+ */
+ @Test
+ public void isBelowThreshold_returnsFalseWhenRssiIsAboveThreshold() {
+ ScanResult scanResult24 = makeScanResult(SAVED_SSID_1, FREQ_24, THRESHOLD_24 + 1);
+ assertFalse(mWakeupEvaluator.isBelowThreshold(scanResult24));
+
+ ScanResult scanResult5 = makeScanResult(SAVED_SSID_1, FREQ_5, THRESHOLD_5 + 1);
+ assertFalse(mWakeupEvaluator.isBelowThreshold(scanResult5));
+ }
+
+ /**
+ * Verify that findViableNetwork does not select ScanResult that is not present in the
+ * WifiConfigurations.
+ */
+ @Test
+ public void findViableNetwork_returnsNullWhenScanResultIsNotInSavedNetworks() {
+ Set<ScanResult> scanResults = Collections.singleton(
+ makeScanResult(UNSAVED_SSID, FREQ_24, THRESHOLD_24 + 1));
+
+ ScanResult scanResult = mWakeupEvaluator.findViableNetwork(scanResults, getSavedNetworks());
+
+ assertNull(scanResult);
+ }
+
+ /**
+ * Verify that findViableNetwork does not select a scan result that is below the threshold.
+ */
+ @Test
+ public void findViableNetwork_returnsNullWhenScanResultIsBelowThreshold() {
+ Set<ScanResult> scanResults = Collections.singleton(
+ makeScanResult(SAVED_SSID_1, FREQ_24, THRESHOLD_24 - 1));
+
+ ScanResult scanResult = mWakeupEvaluator.findViableNetwork(scanResults, getSavedNetworks());
+ assertNull(scanResult);
+ }
+
+ /**
+ * Verify that findViableNetwork returns a viable ScanResult.
+ */
+ @Test
+ public void findViableNetwork_returnsConnectableScanResult() {
+ ScanResult savedScanResult = makeScanResult(SAVED_SSID_1, FREQ_24, THRESHOLD_24 + 1);
+ Set<ScanResult> scanResults = Collections.singleton(savedScanResult);
+
+ ScanResult scanResult = mWakeupEvaluator.findViableNetwork(scanResults, getSavedNetworks());
+ assertEquals(savedScanResult, scanResult);
+ }
+
+ /**
+ * Verify that findViableNetwork returns the viable ScanResult with the highest RSSI.
+ */
+ @Test
+ public void findViableNetwork_returnsConnectableScanResultWithHighestRssi() {
+ ScanResult savedScanResultLow = makeScanResult(SAVED_SSID_1, FREQ_24, THRESHOLD_24 + 1);
+ ScanResult savedScanResultHigh = makeScanResult(SAVED_SSID_1, FREQ_24, THRESHOLD_24 + 10);
+ Set<ScanResult> scanResults = Sets.newArraySet(savedScanResultLow, savedScanResultHigh);
+
+ ScanResult scanResult = mWakeupEvaluator.findViableNetwork(scanResults, getSavedNetworks());
+ assertEquals(savedScanResultHigh, scanResult);
+ }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/WakeupLockTest.java b/tests/wifitests/src/com/android/server/wifi/WakeupLockTest.java
new file mode 100644
index 0000000..7144ecf
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/WakeupLockTest.java
@@ -0,0 +1,214 @@
+/*
+ * 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.ArgumentMatchers.eq;
+import static org.mockito.Mockito.*;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Unit tests for {@link WakeupLock}.
+ */
+public class WakeupLockTest {
+
+ private static final String SSID_1 = "ssid1";
+ private static final String SSID_2 = "ssid2";
+
+ @Mock private WifiConfigManager mWifiConfigManager;
+
+ private ScanResultMatchInfo mNetwork1;
+ private ScanResultMatchInfo mNetwork2;
+ private WakeupLock mWakeupLock;
+
+ /**
+ * Initialize objects before each test run.
+ */
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mNetwork1 = new ScanResultMatchInfo();
+ mNetwork1.networkSsid = SSID_1;
+ mNetwork1.networkType = ScanResultMatchInfo.NETWORK_TYPE_OPEN;
+
+ mNetwork2 = new ScanResultMatchInfo();
+ mNetwork2.networkSsid = SSID_2;
+ mNetwork2.networkType = ScanResultMatchInfo.NETWORK_TYPE_EAP;
+
+ mWakeupLock = new WakeupLock(mWifiConfigManager);
+ }
+
+ /**
+ * Updates the lock enough times to evict any networks not passed in.
+ *
+ * <p>It calls update {@link WakeupLock#CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT} times with
+ * the given network list. It asserts that the lock isn't empty prior to each call to update.
+ */
+ private void updateEnoughTimesToEvictWithAsserts(Collection<ScanResultMatchInfo> networks) {
+ for (int i = 0; i < WakeupLock.CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT; i++) {
+ assertFalse("Lock empty after " + i + " scans", mWakeupLock.isEmpty());
+ mWakeupLock.update(networks);
+ }
+ }
+
+ /**
+ * Updates the lock enough times to evict any networks not passed in.
+ *
+ * <p>It calls update {@link WakeupLock#CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT} times with
+ * the given network list. It does not make any assertions about the state of the lock.
+ */
+ private void updateEnoughTimesToEvictWithoutAsserts(Collection<ScanResultMatchInfo> networks) {
+ for (int i = 0; i < WakeupLock.CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT; i++) {
+ mWakeupLock.update(networks);
+ }
+ }
+
+ /**
+ * Verify that the WakeupLock is not empty immediately after being initialized with networks.
+ */
+ @Test
+ public void verifyNotEmptyWhenInitializedWithNetworkList() {
+ mWakeupLock.initialize(Arrays.asList(mNetwork1, mNetwork2));
+ assertFalse(mWakeupLock.isEmpty());
+ }
+
+ /**
+ * Verify that the WakeupLock is empty when initialized with an empty list.
+ */
+ @Test
+ public void isEmptyWhenInitializedWithEmptyList() {
+ mWakeupLock.initialize(Collections.emptyList());
+ assertTrue(mWakeupLock.isEmpty());
+ }
+
+ /**
+ * Verify that initializing the WakeupLock clears out previous entries.
+ */
+ @Test
+ public void initializingLockClearsPreviousNetworks() {
+ mWakeupLock.initialize(Collections.singletonList(mNetwork1));
+ assertFalse(mWakeupLock.isEmpty());
+
+ mWakeupLock.initialize(Collections.emptyList());
+ assertTrue(mWakeupLock.isEmpty());
+ }
+
+ /**
+ * Updating the lock should evict scan results that haven't been seen in
+ * {@link WakeupLock#CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT} scans.
+ */
+ @Test
+ public void updateShouldRemoveNetworksAfterConsecutiveMissedScans() {
+ mWakeupLock.initialize(Collections.singletonList(mNetwork1));
+
+ updateEnoughTimesToEvictWithAsserts(Collections.singletonList(mNetwork2));
+
+ assertTrue(mWakeupLock.isEmpty());
+ }
+
+ /**
+ * Ensure that missed scans must be consecutive in order to evict networks from lock.
+ */
+ @Test
+ public void updateWithLockedNetworkShouldResetRequiredNumberOfScans() {
+ List<ScanResultMatchInfo> lockedNetworks = Collections.singletonList(mNetwork1);
+ List<ScanResultMatchInfo> updateNetworks = Collections.singletonList(mNetwork2);
+
+ mWakeupLock.initialize(lockedNetworks);
+
+ // one update without network
+ mWakeupLock.update(updateNetworks);
+ // one update with network
+ mWakeupLock.update(lockedNetworks);
+
+ updateEnoughTimesToEvictWithAsserts(updateNetworks);
+
+ assertTrue(mWakeupLock.isEmpty());
+ }
+
+ /**
+ * Once a network is removed from the lock, it should not be reset even if it's seen again.
+ */
+ @Test
+ public void updateWithLockedNetworkAfterItIsRemovedDoesNotReset() {
+ List<ScanResultMatchInfo> lockedNetworks = Collections.singletonList(mNetwork1);
+ mWakeupLock.initialize(lockedNetworks);
+
+ updateEnoughTimesToEvictWithAsserts(Collections.emptyList());
+
+ assertTrue(mWakeupLock.isEmpty());
+ mWakeupLock.update(lockedNetworks);
+ assertTrue(mWakeupLock.isEmpty());
+ }
+
+ /**
+ * Verify that networks can be incrementally removed from the lock. Their counters should be
+ * independent.
+ */
+ @Test
+ public void networksCanBeRemovedIncrementallyFromLock() {
+ List<ScanResultMatchInfo> lockedNetworks = Arrays.asList(mNetwork1, mNetwork2);
+ mWakeupLock.initialize(lockedNetworks);
+
+ updateEnoughTimesToEvictWithAsserts(Collections.singletonList(mNetwork1));
+ assertFalse(mWakeupLock.isEmpty());
+
+ updateEnoughTimesToEvictWithAsserts(Collections.singletonList(mNetwork2));
+ assertTrue(mWakeupLock.isEmpty());
+ }
+
+ /**
+ * Verify that initializing the lock persists the SSID list to the config store.
+ */
+ @Test
+ public void initializeShouldSaveSsidsToStore() {
+ mWakeupLock.initialize(Collections.singletonList(mNetwork1));
+ verify(mWifiConfigManager).saveToStore(eq(false));
+ }
+
+ /**
+ * Verify that update saves to store if the lock changes.
+ */
+ @Test
+ public void updateShouldOnlySaveIfLockChanges() {
+ mWakeupLock.initialize(Collections.singletonList(mNetwork1));
+ updateEnoughTimesToEvictWithoutAsserts(Collections.emptyList());
+
+ // need exactly 2 invocations: 1 for initialize, 1 for successful update
+ verify(mWifiConfigManager, times(2)).saveToStore(eq(false));
+ }
+
+ /**
+ * Verify that update does not save to store if the lock does not change.
+ */
+ @Test
+ public void updateShouldNotSaveIfLockDoesNotChange() {
+ mWakeupLock.update(Collections.singletonList(mNetwork1));
+ verify(mWifiConfigManager, never()).saveToStore(anyBoolean());
+ }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiCertManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiCertManagerTest.java
deleted file mode 100644
index 04c2802..0000000
--- a/tests/wifitests/src/com/android/server/wifi/WifiCertManagerTest.java
+++ /dev/null
@@ -1,143 +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 static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-
-import android.content.Context;
-import android.os.UserHandle;
-import android.security.Credentials;
-import android.security.KeyStore;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.mockito.Mock;
-
-import java.io.File;
-import java.util.Arrays;
-import java.util.HashSet;
-
-/**
- * Unit tests for {@link com.android.server.wifi.WifiCertManager}.
- */
-@SmallTest
-public class WifiCertManagerTest {
- private static final String TAG = "WifiCertManagerTest";
- private byte[] mConfig;
- private String mConfigFile = "";
-
- @Mock private Context mContext;
- @Rule public TemporaryFolder mTempFolder = new TemporaryFolder();
-
- public WifiCertManagerTest() {
- mConfig = null;
- }
-
- @Before
- public void setUp() {
- try {
- File configFile = mTempFolder.newFile();
- mConfigFile = configFile.getAbsolutePath();
- configFile.delete();
- } catch (Exception e) {
- Log.e(TAG, "Failed to construct test", e);
- }
- }
-
- /**
- * This class is created to avoid mocking file system and KeyStore.
- */
- private class TestWifiCertManager extends WifiCertManager {
- private boolean mAffiliatedUser;
-
- public TestWifiCertManager(Context context) {
- super(context, mConfigFile);
- mAffiliatedUser = false;
- }
-
- protected String[] listClientCertsForAllUsers() {
- String prefix = Credentials.USER_PRIVATE_KEY;
- String mockAnswer[] = {prefix + "abc", prefix + "def", prefix + "ghi"};
- return mockAnswer;
- }
-
- protected byte[] readConfigFile() {
- return mConfig;
- }
-
- protected void writeConfigFile(byte[] payload) {
- mConfig = payload;
- }
-
- protected boolean isAffiliatedUser() {
- return mAffiliatedUser;
- }
-
- public void setAffiliatedUser(boolean value) {
- mAffiliatedUser = value;
- }
- }
-
- @Test
- public void testEmptyConfigFile() {
- WifiCertManager certManager = new WifiCertManager(mContext, mConfigFile);
- final String[] expected =
- KeyStore.getInstance().list(
- Credentials.USER_PRIVATE_KEY, UserHandle.myUserId());
- assertArrayEquals(expected, certManager.listClientCertsForCurrentUser());
- }
-
- @Test
- public void testOperations() {
- TestWifiCertManager certManager = new TestWifiCertManager(mContext);
- final HashSet<String> expected1 = new HashSet<>();
- String prefix = Credentials.USER_PRIVATE_KEY;
- expected1.add(prefix + "abc");
- expected1.add(prefix + "def");
- expected1.add(prefix + "ghi");
-
- final HashSet<String> expected2 = new HashSet<>();
- expected2.add(prefix + "abc");
-
- certManager.setAffiliatedUser(false);
- assertEquals(expected1,
- new HashSet<>(Arrays.asList(certManager.listClientCertsForCurrentUser())));
-
- certManager.hideCertFromUnaffiliatedUsers("def");
- certManager.hideCertFromUnaffiliatedUsers("ghi");
- assertEquals(expected2,
- new HashSet<>(Arrays.asList(certManager.listClientCertsForCurrentUser())));
-
- certManager.setAffiliatedUser(true);
- assertEquals(expected1,
- new HashSet<>(Arrays.asList(certManager.listClientCertsForCurrentUser())));
-
- TestWifiCertManager certManager2 = new TestWifiCertManager(mContext);
- certManager2.setAffiliatedUser(false);
- assertEquals(expected2,
- new HashSet<>(Arrays.asList(certManager2.listClientCertsForCurrentUser())));
-
- certManager2.setAffiliatedUser(true);
- assertEquals(expected1,
- new HashSet<>(Arrays.asList(certManager2.listClientCertsForCurrentUser())));
- }
-}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java
index 0fa6600..2baae11 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 "";
@@ -207,13 +210,29 @@
* yet loaded data from store.
*/
@Test
- public void testAddNetworkBeforeLoadFromStore() {
+ public void testAddNetworkIsRejectedBeforeLoadFromStore() {
WifiConfiguration openNetwork = WifiConfigurationTestUtil.createOpenNetwork();
assertFalse(
mWifiConfigManager.addOrUpdateNetwork(openNetwork, TEST_CREATOR_UID).isSuccess());
}
/**
+ * Verifies the {@link WifiConfigManager#saveToStore(boolean)} is rejected until the store has
+ * been read first using {@link WifiConfigManager#loadFromStore()}.
+ */
+ @Test
+ public void testSaveToStoreIsRejectedBeforeLoadFromStore() throws Exception {
+ assertFalse(mWifiConfigManager.saveToStore(true));
+ mContextConfigStoreMockOrder.verify(mWifiConfigStore, never()).write(anyBoolean());
+
+ assertTrue(mWifiConfigManager.loadFromStore());
+ mContextConfigStoreMockOrder.verify(mWifiConfigStore).read();
+
+ assertTrue(mWifiConfigManager.saveToStore(true));
+ mContextConfigStoreMockOrder.verify(mWifiConfigStore).write(anyBoolean());
+ }
+
+ /**
* Verifies the addition of a single network using
* {@link WifiConfigManager#addOrUpdateNetwork(WifiConfiguration, int)}
*/
@@ -793,7 +812,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 +821,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 +873,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 +886,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));
}
@@ -2377,6 +2386,7 @@
* and {@link WifiConfigManager#handleUserUnlock(int)} and ensures that the new store is not
* read until the user is unlocked.
*/
+ @Test
public void testHandleUserSwitchWhenLocked() throws Exception {
int user1 = TEST_DEFAULT_USER;
int user2 = TEST_DEFAULT_USER + 1;
@@ -2415,6 +2425,9 @@
int user2 = TEST_DEFAULT_USER + 1;
setupUserProfiles(user2);
+ // Set up the internal data first.
+ assertTrue(mWifiConfigManager.loadFromStore());
+
// Try stopping background user2 first, this should not do anything.
when(mUserManager.isUserUnlockingOrUnlocked(user2)).thenReturn(false);
mWifiConfigManager.handleUserStop(user2);
@@ -2887,11 +2900,6 @@
verifyAddNetworkToWifiConfigManager(network2);
verifyAddNetworkToWifiConfigManager(network3);
- // Enable all of them.
- assertTrue(mWifiConfigManager.enableNetwork(network1.networkId, false, TEST_CREATOR_UID));
- assertTrue(mWifiConfigManager.enableNetwork(network2.networkId, false, TEST_CREATOR_UID));
- assertTrue(mWifiConfigManager.enableNetwork(network3.networkId, false, TEST_CREATOR_UID));
-
// Now set scan results in 2 of them to set the corresponding
// {@link NetworkSelectionStatus#mSeenInLastQualifiedNetworkSelection} field.
assertTrue(mWifiConfigManager.setNetworkCandidateScanResult(
@@ -2910,15 +2918,6 @@
assertEquals(network3.SSID, hiddenNetworks.get(0).ssid);
assertEquals(network1.SSID, hiddenNetworks.get(1).ssid);
assertEquals(network2.SSID, hiddenNetworks.get(2).ssid);
-
- // Now permanently disable |network3|. This should remove network 3 from the list.
- assertTrue(mWifiConfigManager.disableNetwork(network3.networkId, TEST_CREATOR_UID));
-
- // Retrieve the hidden network list again & verify the order of the networks returned.
- hiddenNetworks = mWifiConfigManager.retrieveHiddenNetworkList();
- assertEquals(2, hiddenNetworks.size());
- assertEquals(network1.SSID, hiddenNetworks.get(0).ssid);
- assertEquals(network2.SSID, hiddenNetworks.get(1).ssid);
}
/**
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/WifiConnectivityManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java
index 4fabd9d..30f823a 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java
@@ -1027,11 +1027,12 @@
* Verify that we perform partial scan when the currently connected network's tx/rx success
* rate is high and when the currently connected network is present in scan
* cache in WifiConfigManager.
+ * WifiConnectivityManager does partial scan only when firmware roaming is not supported.
*
- * Expected behavior: WifiConnectivityManager does full band scan.
+ * Expected behavior: WifiConnectivityManager does partial scan.
*/
@Test
- public void checkSingleScanSettingsWhenConnectedWithHighDataRate() {
+ public void checkPartialScanRequestedWithHighDataRateWithoutFwRoaming() {
mWifiInfo.txSuccessRate = mFullScanMaxTxPacketRate * 2;
mWifiInfo.rxSuccessRate = mFullScanMaxRxPacketRate * 2;
@@ -1044,6 +1045,7 @@
.thenReturn(new WifiConfiguration());
when(mWifiConfigManager.fetchChannelSetForNetworkForPartialScan(anyInt(), anyLong(),
anyInt())).thenReturn(channelList);
+ when(mWifiConnectivityHelper.isFirmwareRoamingSupported()).thenReturn(false);
doAnswer(new AnswerWithArguments() {
public void answer(ScanSettings settings, ScanListener listener,
@@ -1066,6 +1068,52 @@
}
/**
+ * Verify that we skip the partial scan when:
+ * 1. The currently connected network's tx/rx success rate is high.
+ * 2. When the currently connected network is present in scan
+ * cache in WifiConfigManager.
+ * 3. When firmware roaming is supported.
+ * Expected behavior: WifiConnectivityManager does no scan, but periodic scans
+ * are still scheduled.
+ */
+ @Test
+ public void checkPartialScanSkippedWithHighDataRateWithFwRoaming() {
+ mWifiInfo.txSuccessRate = mFullScanMaxTxPacketRate * 2;
+ mWifiInfo.rxSuccessRate = mFullScanMaxRxPacketRate * 2;
+
+ long currentTimeStamp = CURRENT_SYSTEM_TIME_MS;
+ when(mClock.getElapsedSinceBootMillis()).thenReturn(currentTimeStamp);
+
+ final HashSet<Integer> channelList = new HashSet<>();
+ channelList.add(1);
+ channelList.add(2);
+ channelList.add(3);
+
+ when(mWifiStateMachine.getCurrentWifiConfiguration())
+ .thenReturn(new WifiConfiguration());
+ when(mWifiConfigManager.fetchChannelSetForNetworkForPartialScan(anyInt(), anyLong(),
+ anyInt())).thenReturn(channelList);
+ // No scan will be requested when firmware roaming control is not supported.
+ when(mWifiConnectivityHelper.isFirmwareRoamingSupported()).thenReturn(true);
+
+ // Set screen to ON
+ mWifiConnectivityManager.handleScreenStateChanged(true);
+
+ // Set WiFi to connected state to trigger periodic scan
+ mWifiConnectivityManager.handleConnectionStateChanged(
+ WifiConnectivityManager.WIFI_STATE_CONNECTED);
+
+ verify(mWifiScanner, never()).startScan(anyObject(), anyObject(), anyObject());
+
+ // Get the first periodic scan interval to check that we are still scheduling
+ // periodic scans.
+ long firstIntervalMs = mAlarmManager
+ .getTriggerTimeMillis(WifiConnectivityManager.PERIODIC_SCAN_TIMER_TAG)
+ - currentTimeStamp;
+ assertEquals(firstIntervalMs, WifiConnectivityManager.PERIODIC_SCAN_INTERVAL_MS);
+ }
+
+ /**
* Verify that we fall back to full band scan when the currently connected network's tx/rx
* success rate is high and the currently connected network is not present in scan cache in
* WifiConfigManager. This is simulated by returning an empty hashset in |makeChannelList|.
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiControllerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiControllerTest.java
index c7b6180..9d5054e 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiControllerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiControllerTest.java
@@ -88,6 +88,7 @@
@Mock FrameworkFacade mFacade;
@Mock WifiSettingsStore mSettingsStore;
@Mock WifiStateMachine mWifiStateMachine;
+ @Mock WifiStateMachinePrime mWifiStateMachinePrime;
@Mock WifiLockManager mWifiLockManager;
@Mock ContentResolver mContentResolver;
@@ -110,7 +111,8 @@
ArgumentCaptor.forClass(ContentObserver.class);
mWifiController = new WifiController(mContext, mWifiStateMachine,
- mSettingsStore, mWifiLockManager, mLooper.getLooper(), mFacade);
+ mSettingsStore, mWifiLockManager, mLooper.getLooper(), mFacade,
+ mWifiStateMachinePrime);
verify(mFacade, times(3)).registerContentObserver(eq(mContext), any(Uri.class), eq(false),
observerCaptor.capture());
@@ -367,7 +369,8 @@
when(mContext.getContentResolver()).thenReturn(mock(ContentResolver.class));
mWifiController = new WifiController(mContext, mWifiStateMachine,
- mSettingsStore, mWifiLockManager, mLooper.getLooper(), mFacade);
+ mSettingsStore, mWifiLockManager, mLooper.getLooper(), mFacade,
+ mWifiStateMachinePrime);
mWifiController.start();
mLooper.dispatchAll();
@@ -457,11 +460,13 @@
public void testRestartWifiStackDoesNotExitAPMode() throws Exception {
mWifiController.obtainMessage(CMD_SET_AP, 1).sendToTarget();
mLooper.dispatchAll();
+ verify(mWifiStateMachinePrime).enterSoftAPMode(any());
assertEquals("ApEnabledState", getCurrentState().getName());
reset(mWifiStateMachine);
mWifiController.sendMessage(CMD_RESTART_WIFI);
mLooper.dispatchAll();
verifyZeroInteractions(mWifiStateMachine);
+ verify(mWifiStateMachinePrime, never()).disableWifi();
}
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiDiagnosticsTest.java b/tests/wifitests/src/com/android/server/wifi/WifiDiagnosticsTest.java
index 6b93e05..f607b33 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiDiagnosticsTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiDiagnosticsTest.java
@@ -20,6 +20,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.AdditionalMatchers.gt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.contains;
import static org.mockito.Mockito.anyInt;
@@ -119,7 +120,7 @@
/** Verifies that startLogging() registers a logging event handler. */
@Test
public void startLoggingRegistersLogEventHandler() throws Exception {
- final boolean verbosityToggle = false; // even default mode wants log events from HAL
+ final boolean verbosityToggle = false; // even default mode registers handler
mWifiDiagnostics.startLogging(verbosityToggle);
verify(mWifiNative).setLoggingEventHandler(anyObject());
}
@@ -131,7 +132,7 @@
@Test
public void startLoggingRegistersLogEventHandlerIfPriorAttemptFailed()
throws Exception {
- final boolean verbosityToggle = false; // even default mode wants log events from HAL
+ final boolean verbosityToggle = false; // even default mode registers handler
when(mWifiNative.setLoggingEventHandler(anyObject())).thenReturn(false);
mWifiDiagnostics.startLogging(verbosityToggle);
@@ -147,7 +148,7 @@
@Test
public void startLoggingDoesNotRegisterLogEventHandlerIfPriorAttemptSucceeded()
throws Exception {
- final boolean verbosityToggle = false; // even default mode wants log events from HAL
+ final boolean verbosityToggle = false; // even default mode registers handler
when(mWifiNative.setLoggingEventHandler(anyObject())).thenReturn(true);
mWifiDiagnostics.startLogging(verbosityToggle);
@@ -166,19 +167,32 @@
* b) instructs WifiNative to enable ring buffers of the appropriate log level.
*/
@Test
- public void startLoggingStopsAndRestartsRingBufferLogging() throws Exception {
- final boolean verbosityToggle = false;
+ public void startLoggingStopsAndRestartsRingBufferLoggingInVerboseMode() throws Exception {
+ final boolean verbosityToggle = true;
setBuildPropertiesToEnableRingBuffers();
mWifiDiagnostics.startLogging(verbosityToggle);
verify(mWifiNative).startLoggingRingBuffer(
eq(WifiDiagnostics.VERBOSE_NO_LOG), anyInt(), anyInt(), anyInt(),
eq(FAKE_RING_BUFFER_NAME));
verify(mWifiNative).startLoggingRingBuffer(
- eq(WifiDiagnostics.VERBOSE_NORMAL_LOG), anyInt(), anyInt(), anyInt(),
+ eq(WifiDiagnostics.VERBOSE_LOG_WITH_WAKEUP), anyInt(), anyInt(), anyInt(),
eq(FAKE_RING_BUFFER_NAME));
}
@Test
+ public void startLoggingStopsButDoesNotStartRingBufferLoggingInNormalMode() throws Exception {
+ final boolean verbosityToggle = false;
+ setBuildPropertiesToEnableRingBuffers();
+ mWifiDiagnostics.startLogging(verbosityToggle);
+ verify(mWifiNative).startLoggingRingBuffer(
+ eq(WifiDiagnostics.VERBOSE_NO_LOG), anyInt(), anyInt(), anyInt(),
+ eq(FAKE_RING_BUFFER_NAME));
+ verify(mWifiNative, never()).startLoggingRingBuffer(
+ gt(WifiDiagnostics.VERBOSE_NO_LOG), anyInt(), anyInt(), anyInt(),
+ anyString());
+ }
+
+ @Test
public void startLoggingDoesNotStartRingBuffersOnUserBuilds() throws Exception {
final boolean verbosityToggle = true;
mWifiDiagnostics.startLogging(verbosityToggle);
@@ -189,7 +203,7 @@
/** Verifies that, if a log handler was registered, then stopLogging() resets it. */
@Test
public void stopLoggingResetsLogHandlerIfHandlerWasRegistered() throws Exception {
- final boolean verbosityToggle = false; // even default mode wants log events from HAL
+ final boolean verbosityToggle = false; // even default mode registers handler
when(mWifiNative.setLoggingEventHandler(anyObject())).thenReturn(true);
mWifiDiagnostics.startLogging(verbosityToggle);
@@ -202,7 +216,6 @@
/** Verifies that, if a log handler is not registered, stopLogging() skips resetLogHandler(). */
@Test
public void stopLoggingOnlyResetsLogHandlerIfHandlerWasRegistered() throws Exception {
- final boolean verbosityToggle = false; // even default mode wants log events from HAL
mWifiDiagnostics.stopLogging();
verify(mWifiNative, never()).resetLogHandler();
}
@@ -210,7 +223,7 @@
/** Verifies that stopLogging() remembers that we've reset the log handler. */
@Test
public void multipleStopLoggingCallsOnlyResetLogHandlerOnce() throws Exception {
- final boolean verbosityToggle = false; // even default mode wants log events from HAL
+ final boolean verbosityToggle = false; // even default mode registers handler
when(mWifiNative.setLoggingEventHandler(anyObject())).thenReturn(true);
mWifiDiagnostics.startLogging(verbosityToggle);
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiLinkLayerStatsTest.java b/tests/wifitests/src/com/android/server/wifi/WifiLinkLayerStatsTest.java
new file mode 100644
index 0000000..0189aed
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/WifiLinkLayerStatsTest.java
@@ -0,0 +1,124 @@
+/*
+ * 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.assertEquals;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Random;
+
+/**
+ * Unit tests for {@link com.android.server.wifi.WifiLinkLayerStats}.
+ */
+public class WifiLinkLayerStatsTest {
+
+ ExtendedWifiInfo mWifiInfo;
+ WifiLinkLayerStats mWifiLinkLayerStats;
+ Random mRandom = new Random();
+
+ /**
+ * Sets up for unit test
+ */
+ @Before
+ public void setUp() throws Exception {
+ mWifiInfo = new ExtendedWifiInfo();
+ mWifiLinkLayerStats = new WifiLinkLayerStats();
+ }
+
+ /**
+ * Increments the counters
+ *
+ * The values are carved up among the 4 classes (be, bk, vi, vo) so the totals come out right.
+ */
+ private void bumpCounters(WifiLinkLayerStats s, int txg, int txr, int txb, int rxg) {
+ int a = mRandom.nextInt(31);
+ int b = mRandom.nextInt(31);
+ int m0 = a & b;
+ int m1 = a & ~b;
+ int m2 = ~a & b;
+ int m3 = ~a & ~b;
+ assertEquals(-1, m0 + m1 + m2 + m3);
+
+ s.rxmpdu_be += rxg & m0;
+ s.txmpdu_be += txg & m0;
+ s.lostmpdu_be += txb & m0;
+ s.retries_be += txr & m0;
+
+ s.rxmpdu_bk += rxg & m1;
+ s.txmpdu_bk += txg & m1;
+ s.lostmpdu_bk += txb & m1;
+ s.retries_bk += txr & m1;
+
+ s.rxmpdu_vi += rxg & m2;
+ s.txmpdu_vi += txg & m2;
+ s.lostmpdu_vi += txb & m2;
+ s.retries_vi += txr & m2;
+
+ s.rxmpdu_vo += rxg & m3;
+ s.txmpdu_vo += txg & m3;
+ s.lostmpdu_vo += txb & m3;
+ s.retries_vo += txr & m3;
+ }
+
+ /**
+ *
+ * Check that average rates converge to the right values
+ *
+ * Check that the total packet counts are correct
+ *
+ */
+ @Test
+ public void checkThatAverageRatesConvergeToTheRightValuesAndTotalsAreRight() throws Exception {
+ int txg = mRandom.nextInt(1000);
+ int txr = mRandom.nextInt(100);
+ int txb = mRandom.nextInt(100);
+ int rxg = mRandom.nextInt(1000);
+ int n = 3 * 5; // Time constant is 3 seconds, 5 times time constant should get 99% there
+ for (int i = 0; i < n; i++) {
+ bumpCounters(mWifiLinkLayerStats, txg, txr, txb, rxg);
+ mWifiLinkLayerStats.timeStampInMs += 1000;
+ mWifiInfo.updatePacketRates(mWifiLinkLayerStats, mWifiLinkLayerStats.timeStampInMs);
+ }
+ // assertEquals(double, double, double) takes a tolerance as the third argument
+ assertEquals((double) txg, mWifiInfo.txSuccessRate, txg * 0.02);
+ assertEquals((double) txr, mWifiInfo.txRetriesRate, txr * 0.02);
+ assertEquals((double) txb, mWifiInfo.txBadRate, txb * 0.02);
+ assertEquals((double) rxg, mWifiInfo.rxSuccessRate, rxg * 0.02);
+
+ assertEquals(mWifiInfo.txSuccess, n * txg);
+ assertEquals(mWifiInfo.txRetries, n * txr);
+ assertEquals(mWifiInfo.txBad, n * txb);
+ assertEquals(mWifiInfo.rxSuccess, n * rxg);
+ }
+
+ /**
+ * A single packet in a short period of time should have small effect
+ */
+ @Test
+ public void aSinglePacketInAShortPeriodOfTimeShouldHaveSmallEffect() throws Exception {
+ bumpCounters(mWifiLinkLayerStats, 999999999, 999999999, 999999999, 99999999);
+ mWifiLinkLayerStats.timeStampInMs = 999999999;
+ mWifiInfo.updatePacketRates(mWifiLinkLayerStats, mWifiLinkLayerStats.timeStampInMs);
+ assertEquals(0.0, mWifiInfo.txSuccessRate, 0.0001);
+ bumpCounters(mWifiLinkLayerStats, 1, 1, 1, 1);
+ mWifiLinkLayerStats.timeStampInMs += 1;
+ mWifiInfo.updatePacketRates(mWifiLinkLayerStats, mWifiLinkLayerStats.timeStampInMs);
+ assertEquals(0.33, mWifiInfo.txSuccessRate, 0.01);
+ }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiLockManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiLockManagerTest.java
index d5d79b8..1cc9479 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiLockManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiLockManagerTest.java
@@ -31,7 +31,6 @@
import org.junit.Before;
import org.junit.Test;
-
import org.mockito.ArgumentCaptor;
import org.mockito.InOrder;
import org.mockito.Mock;
@@ -52,7 +51,9 @@
WifiLockManager mWifiLockManager;
@Mock IBatteryStats mBatteryStats;
@Mock IBinder mBinder;
+ @Mock IBinder mBinder2;
WorkSource mWorkSource;
+ WorkSource mChainedWorkSource;
@Mock Context mContext;
/**
@@ -62,6 +63,11 @@
@Before
public void setUp() {
mWorkSource = new WorkSource(DEFAULT_TEST_UID_1);
+ mChainedWorkSource = new WorkSource();
+ mChainedWorkSource.createWorkChain()
+ .addNode(DEFAULT_TEST_UID_1, "tag1")
+ .addNode(DEFAULT_TEST_UID_2, "tag2");
+
MockitoAnnotations.initMocks(this);
mWifiLockManager = new WifiLockManager(mContext, mBatteryStats);
}
@@ -225,6 +231,41 @@
}
/**
+ * Checks that WorkChains are preserved when merged WorkSources are created.
+ */
+ @Test
+ public void createMergedworkSourceWithChainsShouldSucceed() throws Exception {
+ acquireWifiLockSuccessful(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "", mBinder, mWorkSource);
+ acquireWifiLockSuccessful(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "", mBinder2,
+ mChainedWorkSource);
+
+ WorkSource merged = mWifiLockManager.createMergedWorkSource();
+ assertEquals(1, merged.size());
+ assertEquals(1, merged.getWorkChains().size());
+ }
+
+ /**
+ * A smoke test for acquiring, updating and releasing WifiLocks with chained WorkSources.
+ */
+ @Test
+ public void smokeTestLockLifecycleWithChainedWorkSource() throws Exception {
+ acquireWifiLockSuccessful(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "", mBinder,
+ mChainedWorkSource);
+
+ WorkSource updated = new WorkSource();
+ updated.set(mChainedWorkSource);
+ updated.createWorkChain().addNode(
+ DEFAULT_TEST_UID_1, "chain2");
+
+ mWifiLockManager.updateWifiLockWorkSource(mBinder, updated);
+ InOrder inOrder = inOrder(mBatteryStats);
+ inOrder.verify(mBatteryStats).noteFullWifiLockReleasedFromSource(mChainedWorkSource);
+ inOrder.verify(mBatteryStats).noteFullWifiLockAcquiredFromSource(eq(updated));
+
+ releaseWifiLockSuccessful(mBinder);
+ }
+
+ /**
* Test the ability to update a WifiLock WorkSource with a new WorkSource.
*
* Steps: acquire a WifiLock with the default test worksource, then attempt to update it.
@@ -314,6 +355,7 @@
assertTrue(wifiLockManagerDumpString.contains("Locks held:"));
assertTrue(wifiLockManagerDumpString.contains(
"WifiLock{" + TEST_WIFI_LOCK_TAG + " type=" + WifiManager.WIFI_MODE_FULL
- + " uid=" + Binder.getCallingUid() + "}"));
+ + " uid=" + Binder.getCallingUid() + " workSource=WorkSource{"
+ + DEFAULT_TEST_UID_1 + "}"));
}
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java b/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java
index 6e0b775..e3e7c0b 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java
@@ -42,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;
@@ -262,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. */
@@ -275,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) {
@@ -558,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);
}
/**
@@ -736,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);
}
/**
@@ -782,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;
@@ -1060,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";
@@ -1108,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>,
@@ -1141,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} /**/
};
@@ -1161,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++) {
@@ -1180,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);
}
/**
@@ -1360,6 +1502,7 @@
* 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/WifiNativeInterfaceManagementTest.java b/tests/wifitests/src/com/android/server/wifi/WifiNativeInterfaceManagementTest.java
new file mode 100644
index 0000000..39ac0fe
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/WifiNativeInterfaceManagementTest.java
@@ -0,0 +1,762 @@
+/*
+ * 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.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
+
+import android.app.test.MockAnswerUtil;
+import android.net.InterfaceConfiguration;
+import android.net.wifi.IApInterface;
+import android.net.wifi.IClientInterface;
+import android.os.INetworkManagementService;
+import android.os.RemoteException;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.server.net.BaseNetworkObserver;
+import com.android.server.wifi.HalDeviceManager.InterfaceDestroyedListener;
+import com.android.server.wifi.WifiNative.SupplicantDeathEventHandler;
+import com.android.server.wifi.WifiNative.VendorHalDeathEventHandler;
+import com.android.server.wifi.WifiNative.WificondDeathEventHandler;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Unit tests for the interface management operations in
+ * {@link com.android.server.wifi.WifiNative}.
+ */
+@SmallTest
+public class WifiNativeInterfaceManagementTest {
+ private static final String IFACE_NAME_0 = "mockWlan0";
+ private static final String IFACE_NAME_1 = "mockWlan1";
+
+ @Mock private WifiVendorHal mWifiVendorHal;
+ @Mock private WificondControl mWificondControl;
+ @Mock private SupplicantStaIfaceHal mSupplicantStaIfaceHal;
+ @Mock private INetworkManagementService mNwManagementService;
+
+ @Mock private WifiNative.StatusListener mStatusListener;
+ @Mock private WifiNative.InterfaceCallback mIfaceCallback0;
+ @Mock private WifiNative.InterfaceCallback mIfaceCallback1;
+
+ private ArgumentCaptor<VendorHalDeathEventHandler> mWifiVendorHalDeathHandlerCaptor =
+ ArgumentCaptor.forClass(VendorHalDeathEventHandler.class);
+ private ArgumentCaptor<WificondDeathEventHandler> mWificondDeathHandlerCaptor =
+ ArgumentCaptor.forClass(WificondDeathEventHandler.class);
+ private ArgumentCaptor<SupplicantDeathEventHandler> mSupplicantDeathHandlerCaptor =
+ ArgumentCaptor.forClass(SupplicantDeathEventHandler.class);
+ private ArgumentCaptor<BaseNetworkObserver> mNetworkObserverCaptor0 =
+ ArgumentCaptor.forClass(BaseNetworkObserver.class);
+ private ArgumentCaptor<BaseNetworkObserver> mNetworkObserverCaptor1 =
+ ArgumentCaptor.forClass(BaseNetworkObserver.class);
+ private ArgumentCaptor<InterfaceDestroyedListener> mIfaceDestroyedListenerCaptor0 =
+ ArgumentCaptor.forClass(InterfaceDestroyedListener.class);
+ private ArgumentCaptor<InterfaceDestroyedListener> mIfaceDestroyedListenerCaptor1 =
+ ArgumentCaptor.forClass(InterfaceDestroyedListener.class);
+
+ private WifiNative mWifiNative;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ // Setup mocks for the positive single interface cases, individual tests can modify the
+ // mocks for negative or multi-interface tests.
+ when(mWifiVendorHal.initialize(mWifiVendorHalDeathHandlerCaptor.capture()))
+ .thenReturn(true);
+ when(mWifiVendorHal.startVendorHal()).thenReturn(true);
+ when(mWifiVendorHal.createStaIface(any())).thenReturn(IFACE_NAME_0);
+ when(mWifiVendorHal.createApIface(any())).thenReturn(IFACE_NAME_0);
+ when(mWifiVendorHal.removeStaIface(any())).thenReturn(true);
+ when(mWifiVendorHal.removeApIface(any())).thenReturn(true);
+
+ when(mWificondControl.registerDeathHandler(mWificondDeathHandlerCaptor.capture()))
+ .thenReturn(true);
+ when(mWificondControl.enableSupplicant()).thenReturn(true);
+ when(mWificondControl.disableSupplicant()).thenReturn(true);
+ when(mWificondControl.setupInterfaceForClientMode(any()))
+ .thenReturn(mock(IClientInterface.class));
+ when(mWificondControl.setupInterfaceForSoftApMode(any()))
+ .thenReturn(mock(IApInterface.class));
+ when(mWificondControl.tearDownClientInterface(any())).thenReturn(true);
+ when(mWificondControl.tearDownSoftApInterface(any())).thenReturn(true);
+ when(mWificondControl.tearDownInterfaces()).thenReturn(true);
+
+ when(mSupplicantStaIfaceHal.registerDeathHandler(mSupplicantDeathHandlerCaptor.capture()))
+ .thenReturn(true);
+ when(mSupplicantStaIfaceHal.deregisterDeathHandler()).thenReturn(true);
+ when(mSupplicantStaIfaceHal.initialize()).thenReturn(true);
+ when(mSupplicantStaIfaceHal.isInitializationStarted()).thenReturn(false);
+ when(mSupplicantStaIfaceHal.isInitializationComplete()).thenReturn(true);
+ when(mSupplicantStaIfaceHal.setupIface(any())).thenReturn(true);
+ when(mSupplicantStaIfaceHal.teardownIface(any())).thenReturn(true);
+
+ mWifiNative = new WifiNative(
+ IFACE_NAME_0, mWifiVendorHal, mSupplicantStaIfaceHal, mWificondControl,
+ mNwManagementService);
+ mWifiNative.initialize();
+ mWifiNative.registerStatusListener(mStatusListener);
+
+ verify(mWifiVendorHal).initialize(any());
+ verify(mWificondControl).registerDeathHandler(any());
+ }
+
+ /**
+ * Verifies the setup of a single client interface.
+ */
+ @Test
+ public void testSetupClientInterface() throws Exception {
+ executeAndValidateSetupClientInterface(
+ false, false, IFACE_NAME_0, mIfaceCallback0, mIfaceDestroyedListenerCaptor0,
+ mNetworkObserverCaptor0);
+ verifyNoMoreInteractions(mWifiVendorHal, mWificondControl, mSupplicantStaIfaceHal,
+ mNwManagementService, mIfaceCallback0, mIfaceCallback1);
+ }
+
+ /**
+ * Verifies the setup of a single softAp interface.
+ */
+ @Test
+ public void testSetupSoftApInterface() throws Exception {
+ executeAndValidateSetupSoftApInterface(
+ false, false, IFACE_NAME_0, mIfaceCallback0, mIfaceDestroyedListenerCaptor0,
+ mNetworkObserverCaptor0);
+ verifyNoMoreInteractions(mWifiVendorHal, mWificondControl, mSupplicantStaIfaceHal,
+ mNwManagementService, mIfaceCallback0, mIfaceCallback1);
+ }
+
+ /**
+ * Verifies the setup & teardown of a single client interface.
+ */
+ @Test
+ public void testSetupAndTeardownClientInterface() throws Exception {
+ executeAndValidateSetupClientInterface(
+ false, false, IFACE_NAME_0, mIfaceCallback0, mIfaceDestroyedListenerCaptor0,
+ mNetworkObserverCaptor0);
+ executeAndValidateTeardownClientInterface(false, false, IFACE_NAME_0, mIfaceCallback0,
+ mIfaceDestroyedListenerCaptor0.getValue(), mNetworkObserverCaptor0.getValue());
+ verifyNoMoreInteractions(mWifiVendorHal, mWificondControl, mSupplicantStaIfaceHal,
+ mNwManagementService, mIfaceCallback0, mIfaceCallback1);
+ }
+
+ /**
+ * Verifies the setup & teardown of a single client interface.
+ */
+ @Test
+ public void testSetupAndTeardownSoftApInterface() throws Exception {
+ executeAndValidateSetupSoftApInterface(
+ false, false, IFACE_NAME_0, mIfaceCallback0, mIfaceDestroyedListenerCaptor0,
+ mNetworkObserverCaptor0);
+ executeAndValidateTeardownSoftApInterface(false, false, IFACE_NAME_0, mIfaceCallback0,
+ mIfaceDestroyedListenerCaptor0.getValue(), mNetworkObserverCaptor0.getValue());
+ verifyNoMoreInteractions(mWifiVendorHal, mWificondControl, mSupplicantStaIfaceHal,
+ mNwManagementService, mIfaceCallback0, mIfaceCallback1);
+ }
+
+ /**
+ * Verifies the setup & teardown of a client & softAp interface.
+ */
+ @Test
+ public void testSetupAndTeardownClientAndSoftApInterface_Seq1() throws Exception {
+ executeAndValidateSetupClientInterface(
+ false, false, IFACE_NAME_0, mIfaceCallback0, mIfaceDestroyedListenerCaptor0,
+ mNetworkObserverCaptor0);
+ executeAndValidateSetupSoftApInterface(
+ true, false, IFACE_NAME_1, mIfaceCallback1, mIfaceDestroyedListenerCaptor1,
+ mNetworkObserverCaptor1);
+ executeAndValidateTeardownClientInterface(false, true, IFACE_NAME_0, mIfaceCallback0,
+ mIfaceDestroyedListenerCaptor0.getValue(), mNetworkObserverCaptor0.getValue());
+ executeAndValidateTeardownSoftApInterface(false, false, IFACE_NAME_1, mIfaceCallback1,
+ mIfaceDestroyedListenerCaptor1.getValue(), mNetworkObserverCaptor1.getValue());
+ verifyNoMoreInteractions(mWifiVendorHal, mWificondControl, mSupplicantStaIfaceHal,
+ mNwManagementService, mIfaceCallback0, mIfaceCallback1);
+ }
+
+ /**
+ * Verifies the setup & teardown of a client & softAp interface.
+ */
+ @Test
+ public void testSetupAndTeardownClientAndSoftApInterface_Seq2() throws Exception {
+ executeAndValidateSetupClientInterface(
+ false, false, IFACE_NAME_0, mIfaceCallback0, mIfaceDestroyedListenerCaptor0,
+ mNetworkObserverCaptor0);
+ executeAndValidateSetupSoftApInterface(
+ true, false, IFACE_NAME_1, mIfaceCallback1, mIfaceDestroyedListenerCaptor1,
+ mNetworkObserverCaptor1);
+ executeAndValidateTeardownSoftApInterface(true, false, IFACE_NAME_1, mIfaceCallback1,
+ mIfaceDestroyedListenerCaptor1.getValue(), mNetworkObserverCaptor1.getValue());
+ executeAndValidateTeardownClientInterface(false, false, IFACE_NAME_0, mIfaceCallback0,
+ mIfaceDestroyedListenerCaptor0.getValue(), mNetworkObserverCaptor0.getValue());
+ verifyNoMoreInteractions(mWifiVendorHal, mWificondControl, mSupplicantStaIfaceHal,
+ mNwManagementService, mIfaceCallback0, mIfaceCallback1);
+ }
+
+ /**
+ * Verifies the setup & teardown of a client & softAp interface.
+ */
+ @Test
+ public void testSetupAndTeardownClientAndSoftApInterface_Seq3() throws Exception {
+ executeAndValidateSetupSoftApInterface(
+ false, false, IFACE_NAME_0, mIfaceCallback0, mIfaceDestroyedListenerCaptor0,
+ mNetworkObserverCaptor0);
+ executeAndValidateSetupClientInterface(
+ false, true, IFACE_NAME_1, mIfaceCallback1, mIfaceDestroyedListenerCaptor1,
+ mNetworkObserverCaptor1);
+ executeAndValidateTeardownSoftApInterface(true, false, IFACE_NAME_0, mIfaceCallback0,
+ mIfaceDestroyedListenerCaptor0.getValue(), mNetworkObserverCaptor0.getValue());
+ executeAndValidateTeardownClientInterface(false, false, IFACE_NAME_1, mIfaceCallback1,
+ mIfaceDestroyedListenerCaptor1.getValue(), mNetworkObserverCaptor1.getValue());
+ verifyNoMoreInteractions(mWifiVendorHal, mWificondControl, mSupplicantStaIfaceHal,
+ mNwManagementService, mIfaceCallback0, mIfaceCallback1);
+ }
+
+ /**
+ * Verifies the setup & teardown of a client & softAp interface.
+ */
+ @Test
+ public void testSetupAndTeardownClientAndSoftApInterface_Seq4() throws Exception {
+ executeAndValidateSetupSoftApInterface(
+ false, false, IFACE_NAME_0, mIfaceCallback0, mIfaceDestroyedListenerCaptor0,
+ mNetworkObserverCaptor0);
+ executeAndValidateSetupClientInterface(
+ false, true, IFACE_NAME_1, mIfaceCallback1, mIfaceDestroyedListenerCaptor1,
+ mNetworkObserverCaptor1);
+ executeAndValidateTeardownClientInterface(false, true, IFACE_NAME_1, mIfaceCallback1,
+ mIfaceDestroyedListenerCaptor1.getValue(), mNetworkObserverCaptor1.getValue());
+ executeAndValidateTeardownSoftApInterface(false, false, IFACE_NAME_0, mIfaceCallback0,
+ mIfaceDestroyedListenerCaptor0.getValue(), mNetworkObserverCaptor0.getValue());
+ verifyNoMoreInteractions(mWifiVendorHal, mWificondControl, mSupplicantStaIfaceHal,
+ mNwManagementService, mIfaceCallback0, mIfaceCallback1);
+ }
+
+ /**
+ * Verifies the setup of a client interface and then a SoftAp interface which would
+ * destroy the Client interface. This is what would happen on older devices which do not
+ * support concurrent interfaces.
+ */
+ @Test
+ public void testSetupClientAndSoftApInterfaceCausesClientInterfaceTeardown() throws Exception {
+ executeAndValidateSetupClientInterface(
+ false, false, IFACE_NAME_0, mIfaceCallback0, mIfaceDestroyedListenerCaptor0,
+ mNetworkObserverCaptor0);
+
+ // Trigger the STA interface teardown when AP interface is created.
+ // The iface name will remain the same.
+ doAnswer(new MockAnswerUtil.AnswerWithArguments() {
+ public String answer(InterfaceDestroyedListener destroyedListener) {
+ mIfaceDestroyedListenerCaptor0.getValue().onDestroyed(IFACE_NAME_0);
+ return IFACE_NAME_0;
+ }
+ }).when(mWifiVendorHal).createApIface(any());
+
+ assertEquals(IFACE_NAME_0, mWifiNative.setupInterfaceForSoftApMode(mIfaceCallback1));
+
+ validateOnDestroyedClientInterface(
+ false, true, IFACE_NAME_0, mIfaceCallback0, mNetworkObserverCaptor0.getValue());
+ validateSetupSoftApInterface(
+ true, false, IFACE_NAME_0, mIfaceDestroyedListenerCaptor1,
+ mNetworkObserverCaptor1);
+
+ // Execute a teardown of the interface to ensure that the new iface removal works.
+ executeAndValidateTeardownSoftApInterface(false, false, IFACE_NAME_0, mIfaceCallback1,
+ mIfaceDestroyedListenerCaptor1.getValue(), mNetworkObserverCaptor1.getValue());
+
+ verifyNoMoreInteractions(mWifiVendorHal, mWificondControl, mSupplicantStaIfaceHal,
+ mNwManagementService, mIfaceCallback0, mIfaceCallback1);
+ }
+
+ /**
+ * Verifies the setup of a client interface and then a SoftAp interface which would
+ * destroy the Client interface. This is what would happen on older devices which do not
+ * support concurrent interfaces.
+ */
+ @Test
+ public void testSetupSoftApAndClientInterfaceCausesSoftApInterfaceTeardown() throws Exception {
+ executeAndValidateSetupSoftApInterface(
+ false, false, IFACE_NAME_0, mIfaceCallback0, mIfaceDestroyedListenerCaptor0,
+ mNetworkObserverCaptor0);
+
+ // Trigger the AP interface teardown when STA interface is created.
+ // The iface name will remain the same.
+ doAnswer(new MockAnswerUtil.AnswerWithArguments() {
+ public String answer(InterfaceDestroyedListener destroyedListener) {
+ mIfaceDestroyedListenerCaptor0.getValue().onDestroyed(IFACE_NAME_0);
+ return IFACE_NAME_0;
+ }
+ }).when(mWifiVendorHal).createStaIface(any());
+
+ assertEquals(IFACE_NAME_0, mWifiNative.setupInterfaceForClientMode(mIfaceCallback1));
+
+ validateOnDestroyedSoftApInterface(
+ true, false, IFACE_NAME_0, mIfaceCallback0, mNetworkObserverCaptor0.getValue());
+ validateSetupClientInterface(
+ false, true, IFACE_NAME_0, mIfaceDestroyedListenerCaptor1,
+ mNetworkObserverCaptor1);
+
+ // Execute a teardown of the interface to ensure that the new iface removal works.
+ executeAndValidateTeardownClientInterface(false, false, IFACE_NAME_0, mIfaceCallback1,
+ mIfaceDestroyedListenerCaptor1.getValue(), mNetworkObserverCaptor1.getValue());
+
+ verifyNoMoreInteractions(mWifiVendorHal, mWificondControl, mSupplicantStaIfaceHal,
+ mNwManagementService, mIfaceCallback0, mIfaceCallback1);
+ }
+
+ /**
+ * Verifies the setup of a client interface and trigger an interface down event.
+ */
+ @Test
+ public void testSetupClientInterfaceAndTriggerInterfaceDown() throws Exception {
+ executeAndValidateSetupSoftApInterface(
+ false, false, IFACE_NAME_0, mIfaceCallback0, mIfaceDestroyedListenerCaptor0,
+ mNetworkObserverCaptor0);
+
+ mNetworkObserverCaptor0.getValue().interfaceLinkStateChanged(IFACE_NAME_0, false);
+ verify(mIfaceCallback0).onDown(IFACE_NAME_0);
+
+ verifyNoMoreInteractions(mWifiVendorHal, mWificondControl, mSupplicantStaIfaceHal,
+ mNwManagementService, mIfaceCallback0, mIfaceCallback1);
+ }
+
+ /**
+ * Verifies the setup of a client interface and trigger an interface up event.
+ */
+ @Test
+ public void testSetupClientInterfaceAndTriggerInterfaceUp() throws Exception {
+ executeAndValidateSetupSoftApInterface(
+ false, false, IFACE_NAME_0, mIfaceCallback0, mIfaceDestroyedListenerCaptor0,
+ mNetworkObserverCaptor0);
+
+ mNetworkObserverCaptor0.getValue().interfaceLinkStateChanged(IFACE_NAME_0, true);
+ verify(mIfaceCallback0).onUp(IFACE_NAME_0);
+
+ verifyNoMoreInteractions(mWifiVendorHal, mWificondControl, mSupplicantStaIfaceHal,
+ mNwManagementService, mIfaceCallback0, mIfaceCallback1);
+ }
+
+ /**
+ * Verifies the setup of a client interface and wificond death handling.
+ */
+ @Test
+ public void testSetupClientInterfaceAndWicondDied() throws Exception {
+ executeAndValidateSetupClientInterface(
+ false, false, IFACE_NAME_0, mIfaceCallback0, mIfaceDestroyedListenerCaptor0,
+ mNetworkObserverCaptor0);
+ // Trigger wificond death
+ mWificondDeathHandlerCaptor.getValue().onDeath();
+
+ validateOnDestroyedClientInterface(false, false, IFACE_NAME_0, mIfaceCallback0,
+ mNetworkObserverCaptor0.getValue());
+
+ verify(mStatusListener).onStatusChanged(false);
+ verify(mStatusListener).onStatusChanged(true);
+ verifyNoMoreInteractions(mWifiVendorHal, mWificondControl, mSupplicantStaIfaceHal,
+ mNwManagementService, mIfaceCallback0, mIfaceCallback1);
+ }
+
+ /**
+ * Verifies the setup of a soft ap interface and vendor HAL death handling.
+ */
+ @Test
+ public void testSetupSoftApInterfaceAndVendorHalDied() throws Exception {
+ executeAndValidateSetupSoftApInterface(
+ false, false, IFACE_NAME_0, mIfaceCallback0, mIfaceDestroyedListenerCaptor0,
+ mNetworkObserverCaptor0);
+ // Trigger vendor HAL death
+ mWifiVendorHalDeathHandlerCaptor.getValue().onDeath();
+
+ validateOnDestroyedSoftApInterface(false, false, IFACE_NAME_0, mIfaceCallback0,
+ mNetworkObserverCaptor0.getValue());
+
+ verify(mStatusListener).onStatusChanged(false);
+ verify(mStatusListener).onStatusChanged(true);
+ verifyNoMoreInteractions(mWifiVendorHal, mWificondControl, mSupplicantStaIfaceHal,
+ mNwManagementService, mIfaceCallback0, mIfaceCallback1);
+ }
+
+ /**
+ * Verifies the setup of a client interface and supplicant HAL death handling.
+ */
+ @Test
+ public void testSetupClientInterfaceAndVendorHalDied() throws Exception {
+ executeAndValidateSetupClientInterface(
+ false, false, IFACE_NAME_0, mIfaceCallback0, mIfaceDestroyedListenerCaptor0,
+ mNetworkObserverCaptor0);
+ // Trigger wificond death
+ mSupplicantDeathHandlerCaptor.getValue().onDeath();
+
+ validateOnDestroyedClientInterface(false, false, IFACE_NAME_0, mIfaceCallback0,
+ mNetworkObserverCaptor0.getValue());
+
+ verify(mStatusListener).onStatusChanged(false);
+ verify(mStatusListener).onStatusChanged(true);
+ verifyNoMoreInteractions(mWifiVendorHal, mWificondControl, mSupplicantStaIfaceHal,
+ mNwManagementService, mIfaceCallback0, mIfaceCallback1);
+ }
+
+ /**
+ * Verifies failure handling in setup of a client interface.
+ */
+ @Test
+ public void testSetupClientInterfaceFailureInStartHal() throws Exception {
+ when(mWifiVendorHal.startVendorHal()).thenReturn(false);
+ assertNull(mWifiNative.setupInterfaceForClientMode(mIfaceCallback0));
+
+ InOrder inOrder = inOrder(mWifiVendorHal, mWificondControl, mSupplicantStaIfaceHal,
+ mNwManagementService);
+ inOrder.verify(mWifiVendorHal).startVendorHal();
+
+ // To test if the failure is handled cleanly, invoke teardown and ensure that
+ // none of the mocks are used because the iface does not exist in the internal
+ // database.
+ mWifiNative.teardownInterface(IFACE_NAME_0);
+
+ verifyNoMoreInteractions(mWifiVendorHal, mWificondControl, mSupplicantStaIfaceHal,
+ mNwManagementService, mIfaceCallback0, mIfaceCallback1);
+ }
+
+ /**
+ * Verifies failure handling in setup of a client interface.
+ */
+ @Test
+ public void testSetupClientInterfaceFailureInStartSupplicant() throws Exception {
+ when(mWificondControl.enableSupplicant()).thenReturn(false);
+ assertNull(mWifiNative.setupInterfaceForClientMode(mIfaceCallback0));
+
+ InOrder inOrder = inOrder(mWifiVendorHal, mWificondControl, mSupplicantStaIfaceHal,
+ mNwManagementService);
+ inOrder.verify(mWifiVendorHal).startVendorHal();
+ inOrder.verify(mWificondControl).enableSupplicant();
+
+ // To test if the failure is handled cleanly, invoke teardown and ensure that
+ // none of the mocks are used because the iface does not exist in the internal
+ // database.
+ mWifiNative.teardownInterface(IFACE_NAME_0);
+
+ verifyNoMoreInteractions(mWifiVendorHal, mWificondControl, mSupplicantStaIfaceHal,
+ mNwManagementService, mIfaceCallback0, mIfaceCallback1);
+ }
+
+ /**
+ * Verifies failure handling in setup of a client interface.
+ */
+ @Test
+ public void testSetupClientInterfaceFailureInHalCreateStaIface() throws Exception {
+ when(mWifiVendorHal.createStaIface(any())).thenReturn(null);
+ assertNull(mWifiNative.setupInterfaceForClientMode(mIfaceCallback0));
+
+ InOrder inOrder = inOrder(mWifiVendorHal, mWificondControl, mSupplicantStaIfaceHal,
+ mNwManagementService);
+ inOrder.verify(mWifiVendorHal).startVendorHal();
+ inOrder.verify(mWificondControl).enableSupplicant();
+ inOrder.verify(mSupplicantStaIfaceHal).isInitializationStarted();
+ inOrder.verify(mSupplicantStaIfaceHal).initialize();
+ inOrder.verify(mSupplicantStaIfaceHal).isInitializationComplete();
+ inOrder.verify(mSupplicantStaIfaceHal).registerDeathHandler(any());
+ inOrder.verify(mWifiVendorHal).createStaIface(any());
+
+ // To test if the failure is handled cleanly, invoke teardown and ensure that
+ // none of the mocks are used because the iface does not exist in the internal
+ // database.
+ mWifiNative.teardownInterface(IFACE_NAME_0);
+
+ verifyNoMoreInteractions(mWifiVendorHal, mWificondControl, mSupplicantStaIfaceHal,
+ mNwManagementService, mIfaceCallback0, mIfaceCallback1);
+ }
+
+ /**
+ * Verifies failure handling in setup of a client interface.
+ */
+ @Test
+ public void testSetupClientInterfaceFailureInWificondSetupInterfaceForClientMode()
+ throws Exception {
+ when(mWificondControl.setupInterfaceForClientMode(any())).thenReturn(null);
+ assertNull(mWifiNative.setupInterfaceForClientMode(mIfaceCallback0));
+
+ InOrder inOrder = inOrder(mWifiVendorHal, mWificondControl, mSupplicantStaIfaceHal,
+ mNwManagementService);
+ inOrder.verify(mWifiVendorHal).startVendorHal();
+ inOrder.verify(mWificondControl).enableSupplicant();
+ inOrder.verify(mSupplicantStaIfaceHal).isInitializationStarted();
+ inOrder.verify(mSupplicantStaIfaceHal).initialize();
+ inOrder.verify(mSupplicantStaIfaceHal).isInitializationComplete();
+ inOrder.verify(mSupplicantStaIfaceHal).registerDeathHandler(any());
+ inOrder.verify(mWifiVendorHal).createStaIface(mIfaceDestroyedListenerCaptor0.capture());
+ inOrder.verify(mWificondControl).setupInterfaceForClientMode(any());
+ inOrder.verify(mWifiVendorHal).removeStaIface(any());
+
+ // Trigger the HAL interface destroyed callback to verify the whole removal sequence.
+ mIfaceDestroyedListenerCaptor0.getValue().onDestroyed(IFACE_NAME_0);
+ validateOnDestroyedClientInterface(false, false, IFACE_NAME_0, mIfaceCallback0,
+ null);
+
+ // To test if the failure is handled cleanly, invoke teardown and ensure that
+ // none of the mocks are used because the iface does not exist in the internal
+ // database.
+ mWifiNative.teardownInterface(IFACE_NAME_0);
+
+ verifyNoMoreInteractions(mWifiVendorHal, mWificondControl, mSupplicantStaIfaceHal,
+ mNwManagementService, mIfaceCallback0, mIfaceCallback1);
+ }
+
+ /**
+ * Verifies failure handling in setup of a client interface.
+ */
+ @Test
+ public void testSetupClientInterfaceFailureInSupplicantSetupIface() throws Exception {
+ when(mSupplicantStaIfaceHal.setupIface(any())).thenReturn(false);
+ assertNull(mWifiNative.setupInterfaceForClientMode(mIfaceCallback0));
+
+ InOrder inOrder = inOrder(mWifiVendorHal, mWificondControl, mSupplicantStaIfaceHal,
+ mNwManagementService);
+ inOrder.verify(mWifiVendorHal).startVendorHal();
+ inOrder.verify(mWificondControl).enableSupplicant();
+ inOrder.verify(mSupplicantStaIfaceHal).isInitializationStarted();
+ inOrder.verify(mSupplicantStaIfaceHal).initialize();
+ inOrder.verify(mSupplicantStaIfaceHal).isInitializationComplete();
+ inOrder.verify(mSupplicantStaIfaceHal).registerDeathHandler(any());
+ inOrder.verify(mWifiVendorHal).createStaIface(mIfaceDestroyedListenerCaptor0.capture());
+ inOrder.verify(mWificondControl).setupInterfaceForClientMode(any());
+ inOrder.verify(mSupplicantStaIfaceHal).setupIface(any());
+ inOrder.verify(mWifiVendorHal).removeStaIface(any());
+
+ // Trigger the HAL interface destroyed callback to verify the whole removal sequence.
+ mIfaceDestroyedListenerCaptor0.getValue().onDestroyed(IFACE_NAME_0);
+ validateOnDestroyedClientInterface(false, false, IFACE_NAME_0, mIfaceCallback0,
+ null);
+
+ // To test if the failure is handled cleanly, invoke teardown and ensure that
+ // none of the mocks are used because the iface does not exist in the internal
+ // database.
+ mWifiNative.teardownInterface(IFACE_NAME_0);
+
+ verifyNoMoreInteractions(mWifiVendorHal, mWificondControl, mSupplicantStaIfaceHal,
+ mNwManagementService, mIfaceCallback0, mIfaceCallback1);
+ }
+
+ /**
+ * Verifies failure handling in setup of a client interface.
+ */
+ @Test
+ public void testSetupClientInterfaceFailureInNetworkObserverRegister() throws Exception {
+ doThrow(new RemoteException()).when(mNwManagementService).registerObserver(any());
+ assertNull(mWifiNative.setupInterfaceForClientMode(mIfaceCallback0));
+
+ InOrder inOrder = inOrder(mWifiVendorHal, mWificondControl, mSupplicantStaIfaceHal,
+ mNwManagementService);
+ inOrder.verify(mWifiVendorHal).startVendorHal();
+ inOrder.verify(mWificondControl).enableSupplicant();
+ inOrder.verify(mSupplicantStaIfaceHal).isInitializationStarted();
+ inOrder.verify(mSupplicantStaIfaceHal).initialize();
+ inOrder.verify(mSupplicantStaIfaceHal).isInitializationComplete();
+ inOrder.verify(mSupplicantStaIfaceHal).registerDeathHandler(any());
+ inOrder.verify(mWifiVendorHal).createStaIface(mIfaceDestroyedListenerCaptor0.capture());
+ inOrder.verify(mWificondControl).setupInterfaceForClientMode(any());
+ inOrder.verify(mSupplicantStaIfaceHal).setupIface(any());
+ inOrder.verify(mNwManagementService).registerObserver(mNetworkObserverCaptor0.capture());
+ inOrder.verify(mWifiVendorHal).removeStaIface(any());
+
+ // Trigger the HAL interface destroyed callback to verify the whole removal sequence.
+ mIfaceDestroyedListenerCaptor0.getValue().onDestroyed(IFACE_NAME_0);
+ validateOnDestroyedClientInterface(false, false, IFACE_NAME_0, mIfaceCallback0,
+ mNetworkObserverCaptor0.getValue());
+
+ // To test if the failure is handled cleanly, invoke teardown and ensure that
+ // none of the mocks are used because the iface does not exist in the internal
+ // database.
+ mWifiNative.teardownInterface(IFACE_NAME_0);
+
+ verifyNoMoreInteractions(mWifiVendorHal, mWificondControl, mSupplicantStaIfaceHal,
+ mNwManagementService, mIfaceCallback0, mIfaceCallback1);
+ }
+
+ /**
+ * Verifies the interface state query API.
+ */
+ @Test
+ public void testIsInterfaceUp() throws Exception {
+ executeAndValidateSetupClientInterface(
+ false, false, IFACE_NAME_0, mIfaceCallback0, mIfaceDestroyedListenerCaptor0,
+ mNetworkObserverCaptor0);
+
+ InterfaceConfiguration config = new InterfaceConfiguration();
+ when(mNwManagementService.getInterfaceConfig(IFACE_NAME_0)).thenReturn(config);
+
+ config.setInterfaceUp();
+ assertTrue(mWifiNative.isInterfaceUp(IFACE_NAME_0));
+
+ config.setInterfaceDown();
+ assertFalse(mWifiNative.isInterfaceUp(IFACE_NAME_0));
+
+ when(mNwManagementService.getInterfaceConfig(IFACE_NAME_0)).thenReturn(null);
+ assertFalse(mWifiNative.isInterfaceUp(IFACE_NAME_0));
+
+ verify(mNwManagementService, times(3)).getInterfaceConfig(IFACE_NAME_0);
+
+ verifyNoMoreInteractions(mWifiVendorHal, mWificondControl, mSupplicantStaIfaceHal,
+ mNwManagementService, mIfaceCallback0, mIfaceCallback1);
+ }
+
+ private void executeAndValidateSetupClientInterface(
+ boolean existingStaIface, boolean existingApIface,
+ String ifaceName, @Mock WifiNative.InterfaceCallback callback,
+ ArgumentCaptor<InterfaceDestroyedListener> destroyedListenerCaptor,
+ ArgumentCaptor<BaseNetworkObserver> networkObserverCaptor) throws Exception {
+ when(mWifiVendorHal.createStaIface(any())).thenReturn(ifaceName);
+ assertEquals(ifaceName, mWifiNative.setupInterfaceForClientMode(callback));
+
+ validateSetupClientInterface(
+ existingStaIface, existingApIface, ifaceName, destroyedListenerCaptor,
+ networkObserverCaptor);
+ }
+
+ private void validateSetupClientInterface(
+ boolean existingStaIface, boolean existingApIface,
+ String ifaceName, ArgumentCaptor<InterfaceDestroyedListener> destroyedListenerCaptor,
+ ArgumentCaptor<BaseNetworkObserver> networkObserverCaptor) throws Exception {
+ InOrder inOrder = inOrder(mWifiVendorHal, mWificondControl, mSupplicantStaIfaceHal,
+ mNwManagementService);
+
+ if (!existingStaIface && !existingApIface) {
+ inOrder.verify(mWifiVendorHal).startVendorHal();
+ }
+ if (!existingStaIface) {
+ inOrder.verify(mWificondControl).enableSupplicant();
+ inOrder.verify(mSupplicantStaIfaceHal).isInitializationStarted();
+ inOrder.verify(mSupplicantStaIfaceHal).initialize();
+ inOrder.verify(mSupplicantStaIfaceHal).isInitializationComplete();
+ inOrder.verify(mSupplicantStaIfaceHal).registerDeathHandler(any());
+ }
+ inOrder.verify(mWifiVendorHal).createStaIface(destroyedListenerCaptor.capture());
+ inOrder.verify(mWificondControl).setupInterfaceForClientMode(ifaceName);
+ inOrder.verify(mSupplicantStaIfaceHal).setupIface(ifaceName);
+ inOrder.verify(mNwManagementService).registerObserver(networkObserverCaptor.capture());
+ inOrder.verify(mNwManagementService).clearInterfaceAddresses(ifaceName);
+ inOrder.verify(mNwManagementService).setInterfaceIpv6PrivacyExtensions(ifaceName, true);
+ inOrder.verify(mNwManagementService).disableIpv6(ifaceName);
+ }
+
+ private void executeAndValidateTeardownClientInterface(
+ boolean anyOtherStaIface, boolean anyOtherApIface,
+ String ifaceName, @Mock WifiNative.InterfaceCallback callback,
+ InterfaceDestroyedListener destroyedListener,
+ BaseNetworkObserver networkObserver) throws Exception {
+ InOrder inOrder = inOrder(mWifiVendorHal, mWificondControl, mSupplicantStaIfaceHal,
+ mNwManagementService, callback);
+
+ mWifiNative.teardownInterface(ifaceName);
+
+ inOrder.verify(mWifiVendorHal).removeStaIface(ifaceName);
+
+ // Now trigger the HalDeviceManager destroy callback to initiate the rest of the teardown.
+ destroyedListener.onDestroyed(ifaceName);
+
+ validateOnDestroyedClientInterface(
+ anyOtherStaIface, anyOtherApIface, ifaceName, callback, networkObserver);
+ }
+
+ private void validateOnDestroyedClientInterface(
+ boolean anyOtherStaIface, boolean anyOtherApIface,
+ String ifaceName, @Mock WifiNative.InterfaceCallback callback,
+ BaseNetworkObserver networkObserver) throws Exception {
+ InOrder inOrder = inOrder(mWifiVendorHal, mWificondControl, mSupplicantStaIfaceHal,
+ mNwManagementService, callback);
+
+ inOrder.verify(mNwManagementService).unregisterObserver(networkObserver);
+ inOrder.verify(mSupplicantStaIfaceHal).teardownIface(ifaceName);
+ inOrder.verify(mWificondControl).tearDownClientInterface(ifaceName);
+
+ if (!anyOtherStaIface) {
+ inOrder.verify(mSupplicantStaIfaceHal).deregisterDeathHandler();
+ inOrder.verify(mWificondControl).disableSupplicant();
+ }
+ if (!anyOtherStaIface && !anyOtherApIface) {
+ inOrder.verify(mWificondControl).tearDownInterfaces();
+ inOrder.verify(mWifiVendorHal).stopVendorHal();
+ }
+ inOrder.verify(callback).onDestroyed(ifaceName);
+ }
+
+ private void executeAndValidateSetupSoftApInterface(
+ boolean existingStaIface, boolean existingApIface,
+ String ifaceName, @Mock WifiNative.InterfaceCallback callback,
+ ArgumentCaptor<InterfaceDestroyedListener> destroyedListenerCaptor,
+ ArgumentCaptor<BaseNetworkObserver> networkObserverCaptor) throws Exception {
+ when(mWifiVendorHal.createApIface(any())).thenReturn(ifaceName);
+ assertEquals(ifaceName, mWifiNative.setupInterfaceForSoftApMode(callback));
+
+ validateSetupSoftApInterface(
+ existingStaIface, existingApIface, ifaceName, destroyedListenerCaptor,
+ networkObserverCaptor);
+ }
+
+ private void validateSetupSoftApInterface(
+ boolean existingStaIface, boolean existingApIface,
+ String ifaceName, ArgumentCaptor<InterfaceDestroyedListener> destroyedListenerCaptor,
+ ArgumentCaptor<BaseNetworkObserver> networkObserverCaptor) throws Exception {
+ InOrder inOrder = inOrder(mWifiVendorHal, mWificondControl, mNwManagementService);
+
+ if (!existingStaIface && !existingApIface) {
+ inOrder.verify(mWifiVendorHal).startVendorHal();
+ }
+ inOrder.verify(mWifiVendorHal).createApIface(destroyedListenerCaptor.capture());
+ inOrder.verify(mWificondControl).setupInterfaceForSoftApMode(ifaceName);
+ inOrder.verify(mNwManagementService).registerObserver(networkObserverCaptor.capture());
+ }
+
+ private void executeAndValidateTeardownSoftApInterface(
+ boolean anyOtherStaIface, boolean anyOtherApIface,
+ String ifaceName, @Mock WifiNative.InterfaceCallback callback,
+ InterfaceDestroyedListener destroyedListener,
+ BaseNetworkObserver networkObserver) throws Exception {
+ InOrder inOrder = inOrder(mWifiVendorHal, mWificondControl, mNwManagementService, callback);
+
+ mWifiNative.teardownInterface(ifaceName);
+
+ inOrder.verify(mWifiVendorHal).removeApIface(ifaceName);
+
+ // Now trigger the HalDeviceManager destroy callback to initiate the rest of the teardown.
+ destroyedListener.onDestroyed(ifaceName);
+
+ validateOnDestroyedSoftApInterface(
+ anyOtherStaIface, anyOtherApIface, ifaceName, callback, networkObserver);
+ }
+
+ private void validateOnDestroyedSoftApInterface(
+ boolean anyOtherStaIface, boolean anyOtherApIface,
+ String ifaceName, @Mock WifiNative.InterfaceCallback callback,
+ BaseNetworkObserver networkObserver) throws Exception {
+ InOrder inOrder = inOrder(mWifiVendorHal, mWificondControl, mNwManagementService, callback);
+
+ inOrder.verify(mNwManagementService).unregisterObserver(networkObserver);
+ inOrder.verify(mWificondControl).stopSoftAp(ifaceName);
+ inOrder.verify(mWificondControl).tearDownSoftApInterface(ifaceName);
+
+ if (!anyOtherStaIface && !anyOtherApIface) {
+ inOrder.verify(mWificondControl).tearDownInterfaces();
+ inOrder.verify(mWifiVendorHal).stopVendorHal();
+ }
+ inOrder.verify(callback).onDestroyed(ifaceName);
+ }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiNativeTest.java b/tests/wifitests/src/com/android/server/wifi/WifiNativeTest.java
index 32d1daa..4c2b6f7 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;
@@ -30,6 +28,7 @@
import android.net.wifi.IApInterface;
import android.net.wifi.IClientInterface;
import android.net.wifi.WifiConfiguration;
+import android.os.INetworkManagementService;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Pair;
@@ -47,6 +46,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};
@@ -149,14 +149,17 @@
@Mock private WifiVendorHal mWifiVendorHal;
@Mock private WificondControl mWificondControl;
@Mock private SupplicantStaIfaceHal mStaIfaceHal;
+ @Mock private INetworkManagementService mNwService;
private WifiNative mWifiNative;
@Before
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, mNwService);
}
/**
@@ -481,127 +484,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 +672,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 +684,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 +697,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 +707,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 +717,7 @@
@Test
public void testStopPnoScan() throws Exception {
mWifiNative.stopPnoScan();
- verify(mWificondControl).stopPnoScan();
+ verify(mWificondControl).stopPnoScan(WIFI_IFACE_NAME);
}
/**
@@ -709,8 +728,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 +740,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/WifiNetworkSelectorTest.java b/tests/wifitests/src/com/android/server/wifi/WifiNetworkSelectorTest.java
index 3d3af36..b56da5d 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiNetworkSelectorTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiNetworkSelectorTest.java
@@ -613,8 +613,8 @@
// Rssi after connected.
when(mWifiInfo.getRssi()).thenReturn(mThresholdQualifiedRssi2G + 1);
// No streaming traffic.
- when(mWifiInfo.getTxSuccessRatePps()).thenReturn(0.0);
- when(mWifiInfo.getRxSuccessRatePps()).thenReturn(0.0);
+ mWifiInfo.txSuccessRate = 0.0;
+ mWifiInfo.rxSuccessRate = 0.0;
// Do not perform selection on 2GHz if current network is good and no 5GHz available
testStayOrTryToSwitch(
@@ -640,8 +640,8 @@
// Rssi after connected.
when(mWifiInfo.getRssi()).thenReturn(mThresholdQualifiedRssi2G + 1);
// No streaming traffic.
- when(mWifiInfo.getTxSuccessRatePps()).thenReturn(0.0);
- when(mWifiInfo.getRxSuccessRatePps()).thenReturn(0.0);
+ mWifiInfo.txSuccessRate = 0.0;
+ mWifiInfo.rxSuccessRate = 0.0;
// When on 2GHz, even with "good" signal strength, run selection if 5GHz available
testStayOrTryToSwitch(
@@ -670,8 +670,8 @@
// Rssi after connected.
when(mWifiInfo.getRssi()).thenReturn(mThresholdQualifiedRssi5G - 1);
// No streaming traffic.
- when(mWifiInfo.getTxSuccessRatePps()).thenReturn(0.0);
- when(mWifiInfo.getRxSuccessRatePps()).thenReturn(0.0);
+ mWifiInfo.txSuccessRate = 0.0;
+ mWifiInfo.rxSuccessRate = 0.0;
// Run Selection when the current 5Ghz network has low RSSI.
testStayOrTryToSwitch(
@@ -695,8 +695,8 @@
// Rssi after connected.
when(mWifiInfo.getRssi()).thenReturn(mThresholdQualifiedRssi5G + 1);
// No streaming traffic.
- when(mWifiInfo.getTxSuccessRatePps()).thenReturn(0.0);
- when(mWifiInfo.getRxSuccessRatePps()).thenReturn(0.0);
+ mWifiInfo.txSuccessRate = 0.0;
+ mWifiInfo.rxSuccessRate = 0.0;
// Connected to a high quality 5Ghz network, so the other result is irrelevant
testStayOrTryToSwitch(
@@ -719,8 +719,8 @@
// Rssi after connected.
when(mWifiInfo.getRssi()).thenReturn(mThresholdQualifiedRssi2G + 1);
// No streaming traffic.
- when(mWifiInfo.getTxSuccessRatePps()).thenReturn(0.0);
- when(mWifiInfo.getRxSuccessRatePps()).thenReturn(0.0);
+ mWifiInfo.txSuccessRate = 0.0;
+ mWifiInfo.rxSuccessRate = 0.0;
testStayOrTryToSwitch(
// Parameters for network1:
@@ -747,8 +747,8 @@
// Rssi after connected.
when(mWifiInfo.getRssi()).thenReturn(mThresholdQualifiedRssi2G - 1);
// No streaming traffic.
- when(mWifiInfo.getTxSuccessRatePps()).thenReturn(0.0);
- when(mWifiInfo.getRxSuccessRatePps()).thenReturn(0.0);
+ mWifiInfo.txSuccessRate = 0.0;
+ mWifiInfo.rxSuccessRate = 0.0;
testStayOrTryToSwitch(
mThresholdQualifiedRssi2G + 1 /* rssi before connected */,
@@ -769,9 +769,8 @@
// Rssi after connected.
when(mWifiInfo.getRssi()).thenReturn(mThresholdQualifiedRssi2G + 1);
// Streaming traffic
- when(mWifiInfo.getTxSuccessRatePps()).thenReturn(
- (double) (mStayOnNetworkMinimumTxRate + 1));
- when(mWifiInfo.getRxSuccessRatePps()).thenReturn(0.0);
+ mWifiInfo.txSuccessRate = ((double) (mStayOnNetworkMinimumTxRate + 1));
+ mWifiInfo.rxSuccessRate = 0.0;
testStayOrTryToSwitch(
mThresholdQualifiedRssi2G + 1 /* rssi before connected */,
@@ -792,9 +791,8 @@
// Rssi after connected.
when(mWifiInfo.getRssi()).thenReturn(mThresholdQualifiedRssi2G + 1);
// Streaming traffic
- when(mWifiInfo.getTxSuccessRatePps()).thenReturn(0.0);
- when(mWifiInfo.getRxSuccessRatePps()).thenReturn(
- (double) (mStayOnNetworkMinimumRxRate + 1));
+ mWifiInfo.txSuccessRate = 0.0;
+ mWifiInfo.rxSuccessRate = ((double) (mStayOnNetworkMinimumRxRate + 1));
testStayOrTryToSwitch(
mThresholdQualifiedRssi2G + 1 /* rssi before connected */,
@@ -815,9 +813,8 @@
// Rssi after connected.
when(mWifiInfo.getRssi()).thenReturn(mThresholdQualifiedRssi5G + 1);
// Streaming traffic
- when(mWifiInfo.getTxSuccessRatePps()).thenReturn(
- (double) (mStayOnNetworkMinimumTxRate + 1));
- when(mWifiInfo.getRxSuccessRatePps()).thenReturn(0.0);
+ mWifiInfo.txSuccessRate = ((double) (mStayOnNetworkMinimumTxRate + 1));
+ mWifiInfo.rxSuccessRate = 0.0;
testStayOrTryToSwitch(
mThresholdQualifiedRssi5G + 1 /* rssi before connected */,
@@ -838,9 +835,8 @@
// Rssi after connected.
when(mWifiInfo.getRssi()).thenReturn(mThresholdQualifiedRssi5G + 1);
// Streaming traffic
- when(mWifiInfo.getTxSuccessRatePps()).thenReturn(0.0);
- when(mWifiInfo.getRxSuccessRatePps()).thenReturn(
- (double) (mStayOnNetworkMinimumRxRate + 1));
+ mWifiInfo.txSuccessRate = 0.0;
+ mWifiInfo.rxSuccessRate = ((double) (mStayOnNetworkMinimumRxRate + 1));
testStayOrTryToSwitch(
mThresholdQualifiedRssi5G + 1 /* rssi before connected */,
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..52281df 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java
@@ -31,6 +31,7 @@
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 android.net.wifi.WifiManager.WIFI_STATE_DISABLED;
import static android.provider.Settings.Secure.LOCATION_MODE_HIGH_ACCURACY;
@@ -45,6 +46,7 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
@@ -64,6 +66,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 +87,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 +123,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 +132,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 +145,7 @@
@Mock Context mContext;
@Mock WifiInjector mWifiInjector;
+ @Mock WifiCountryCode mWifiCountryCode;
@Mock Clock mClock;
@Mock WifiController mWifiController;
@Mock WifiTrafficPoller mWifiTrafficPoller;
@@ -163,6 +170,7 @@
@Mock IBinder mAppBinder;
@Mock LocalOnlyHotspotRequestInfo mRequestInfo;
@Mock LocalOnlyHotspotRequestInfo mRequestInfo2;
+ @Mock IProvisioningCallback mProvisioningCallback;
@Spy FakeWifiLog mLog;
@@ -236,6 +244,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 +286,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);
}
@@ -357,10 +372,11 @@
/**
* Verify that wifi can be enabled by a caller with WIFI_STATE_CHANGE permission when wifi is
* off (no hotspot, no airplane mode).
+ *
+ * Note: hotspot is disabled by default
*/
@Test
public void testSetWifiEnabledSuccess() throws Exception {
- when(mWifiStateMachine.syncGetWifiApState()).thenReturn(WifiManager.WIFI_AP_STATE_DISABLED);
when(mSettingsStore.handleWifiToggled(eq(true))).thenReturn(true);
when(mSettingsStore.isAirplaneModeOn()).thenReturn(false);
assertTrue(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, true));
@@ -372,7 +388,6 @@
*/
@Test
public void testSetWifiEnabledNoToggle() throws Exception {
- when(mWifiStateMachine.syncGetWifiApState()).thenReturn(WifiManager.WIFI_AP_STATE_DISABLED);
when(mSettingsStore.handleWifiToggled(eq(true))).thenReturn(false);
assertTrue(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, true));
verify(mWifiController, never()).sendMessage(eq(CMD_WIFI_TOGGLED));
@@ -389,7 +404,6 @@
eq("WifiService"));
when(mSettingsStore.isAirplaneModeOn()).thenReturn(false);
mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, true);
- verify(mWifiStateMachine, never()).syncGetWifiApState();
}
/**
@@ -428,7 +442,17 @@
*/
@Test
public void testSetWifiEnabledFromNetworkSettingsHolderWhenApEnabled() throws Exception {
- when(mWifiStateMachine.syncGetWifiApState()).thenReturn(WifiManager.WIFI_AP_STATE_ENABLED);
+ when(mFrameworkFacade.inStorageManagerCryptKeeperBounce()).thenReturn(false);
+ when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false);
+ mWifiServiceImpl.checkAndStartWifi();
+
+ verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(),
+ (IntentFilter) argThat(new IntentFilterMatcher()));
+
+ TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext,
+ WIFI_AP_STATE_ENABLED, WIFI_AP_STATE_ENABLING, SAP_START_FAILURE_GENERAL,
+ WIFI_IFACE_NAME, IFACE_IP_MODE_LOCAL_ONLY);
+
when(mSettingsStore.handleWifiToggled(eq(true))).thenReturn(true);
when(mContext.checkPermission(
eq(android.Manifest.permission.NETWORK_SETTINGS), anyInt(), anyInt()))
@@ -443,7 +467,17 @@
*/
@Test
public void testSetWifiEnabledFromAppFailsWhenApEnabled() throws Exception {
- when(mWifiStateMachine.syncGetWifiApState()).thenReturn(WifiManager.WIFI_AP_STATE_ENABLED);
+ when(mFrameworkFacade.inStorageManagerCryptKeeperBounce()).thenReturn(false);
+ when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false);
+ mWifiServiceImpl.checkAndStartWifi();
+
+ verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(),
+ (IntentFilter) argThat(new IntentFilterMatcher()));
+
+ TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext,
+ WIFI_AP_STATE_ENABLED, WIFI_AP_STATE_ENABLING, SAP_START_FAILURE_GENERAL,
+ WIFI_IFACE_NAME, IFACE_IP_MODE_LOCAL_ONLY);
+
when(mContext.checkPermission(
eq(android.Manifest.permission.NETWORK_SETTINGS), anyInt(), anyInt()))
.thenReturn(PackageManager.PERMISSION_DENIED);
@@ -459,7 +493,6 @@
*/
@Test
public void testSetWifiDisabledSuccess() throws Exception {
- when(mWifiStateMachine.syncGetWifiApState()).thenReturn(WifiManager.WIFI_AP_STATE_DISABLED);
when(mSettingsStore.handleWifiToggled(eq(false))).thenReturn(true);
assertTrue(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, false));
verify(mWifiController).sendMessage(eq(CMD_WIFI_TOGGLED));
@@ -470,7 +503,6 @@
*/
@Test
public void testSetWifiDisabledNoToggle() throws Exception {
- when(mWifiStateMachine.syncGetWifiApState()).thenReturn(WifiManager.WIFI_AP_STATE_DISABLED);
when(mSettingsStore.handleWifiToggled(eq(false))).thenReturn(false);
assertTrue(mWifiServiceImpl.setWifiEnabled(TEST_PACKAGE_NAME, false));
verify(mWifiController, never()).sendMessage(eq(CMD_WIFI_TOGGLED));
@@ -482,7 +514,6 @@
*/
@Test(expected = SecurityException.class)
public void testSetWifiDisabledWithoutPermission() throws Exception {
- when(mWifiStateMachine.syncGetWifiApState()).thenReturn(WifiManager.WIFI_AP_STATE_DISABLED);
doThrow(new SecurityException()).when(mContext)
.enforceCallingOrSelfPermission(eq(android.Manifest.permission.CHANGE_WIFI_STATE),
eq("WifiService"));
@@ -547,6 +578,58 @@
}
/**
+ * Ensure we return the proper variable for the softap state after getting an AP state change
+ * broadcast.
+ */
+ @Test
+ public void testGetWifiApEnabled() {
+ // set up WifiServiceImpl with a live thread for testing
+ HandlerThread serviceHandlerThread = new HandlerThread("ServiceHandlerThreadForTest");
+ serviceHandlerThread.start();
+ when(mWifiInjector.getWifiServiceHandlerThread()).thenReturn(serviceHandlerThread);
+ mWifiServiceImpl = new WifiServiceImpl(mContext, mWifiInjector, mAsyncChannel);
+ mWifiServiceImpl.setWifiHandlerLogForTest(mLog);
+
+ // ap should be disabled when wifi hasn't been started
+ assertEquals(WifiManager.WIFI_AP_STATE_DISABLED, mWifiServiceImpl.getWifiApEnabledState());
+
+ when(mFrameworkFacade.inStorageManagerCryptKeeperBounce()).thenReturn(false);
+ when(mSettingsStore.isWifiToggleEnabled()).thenReturn(false);
+ mWifiServiceImpl.checkAndStartWifi();
+ mLooper.dispatchAll();
+
+ // ap should be disabled initially
+ assertEquals(WifiManager.WIFI_AP_STATE_DISABLED, mWifiServiceImpl.getWifiApEnabledState());
+
+ // send an ap state change to verify WifiServiceImpl is updated
+ verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(),
+ (IntentFilter) argThat(new IntentFilterMatcher()));
+
+ TestUtil.sendWifiApStateChanged(mBroadcastReceiverCaptor.getValue(), mContext,
+ WIFI_AP_STATE_FAILED, WIFI_AP_STATE_DISABLED, SAP_START_FAILURE_GENERAL,
+ WIFI_IFACE_NAME, IFACE_IP_MODE_LOCAL_ONLY);
+ mLooper.dispatchAll();
+
+ assertEquals(WifiManager.WIFI_AP_STATE_FAILED, mWifiServiceImpl.getWifiApEnabledState());
+ }
+
+ /**
+ * Ensure we do not allow unpermitted callers to get the wifi ap state.
+ */
+ @Test
+ public void testGetWifiApEnabledPermissionDenied() {
+ // we should not be able to get the state
+ doThrow(new SecurityException()).when(mContext)
+ .enforceCallingOrSelfPermission(eq(android.Manifest.permission.ACCESS_WIFI_STATE),
+ eq("WifiService"));
+
+ try {
+ mWifiServiceImpl.getWifiApEnabledState();
+ fail("expected SecurityException");
+ } catch (SecurityException expected) { }
+ }
+
+ /**
* Make sure we do not start wifi if System services have to be restarted to decrypt the device.
*/
@Test
@@ -578,7 +661,6 @@
when(mSettingsStore.handleWifiToggled(true)).thenReturn(true);
when(mSettingsStore.isWifiToggleEnabled()).thenReturn(true);
when(mWifiStateMachine.syncGetWifiState()).thenReturn(WIFI_STATE_DISABLED);
- when(mWifiStateMachine.syncGetWifiApState()).thenReturn(WifiManager.WIFI_AP_STATE_DISABLED);
when(mContext.getPackageName()).thenReturn(ANDROID_SYSTEM_PACKAGE);
mWifiServiceImpl.checkAndStartWifi();
verify(mWifiController).start();
@@ -586,94 +668,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
@@ -1183,7 +1177,7 @@
IFACE_IP_MODE_LOCAL_ONLY);
mLooper.dispatchAll();
- verifyNoMoreInteractions(mHandler);
+ verify(mHandler, never()).handleMessage(any(Message.class));
}
/**
@@ -1600,6 +1594,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 +1688,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 +1890,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..0c5db44 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiStateMachinePrimeTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiStateMachinePrimeTest.java
@@ -19,8 +19,6 @@
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.*;
-import android.net.wifi.IApInterface;
-import android.net.wifi.IWificond;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.os.INetworkManagementService;
@@ -50,12 +48,12 @@
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;
- @Mock IApInterface mApInterface;
@Mock INetworkManagementService mNMService;
@Mock SoftApManager mSoftApManager;
SoftApManager.Listener mSoftApListener;
@@ -71,13 +69,18 @@
MockitoAnnotations.initMocks(this);
mLooper = new TestLooper();
- mWifiInjector = mock(WifiInjector.class);
+ when(mWifiInjector.getWifiNative()).thenReturn(mWifiNative);
+ when(mWifiNative.getInterfaceName()).thenReturn(WIFI_IFACE_NAME);
mWifiStateMachinePrime = createWifiStateMachinePrime();
+
+ // creating a new WSMP cleans up any existing interfaces, check and reset expectations
+ verifyCleanupCalled();
+ reset(mWifiNative);
}
private WifiStateMachinePrime createWifiStateMachinePrime() {
- when(mWifiInjector.makeWificond()).thenReturn(null);
- return new WifiStateMachinePrime(mWifiInjector, mLooper.getLooper(), mNMService);
+ return new WifiStateMachinePrime(mWifiInjector, mLooper.getLooper(),
+ mWifiNative, mNMService);
}
/**
@@ -89,7 +92,8 @@
}
private void enterSoftApActiveMode() throws Exception {
- enterSoftApActiveMode(null);
+ enterSoftApActiveMode(
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null));
}
/**
@@ -97,46 +101,48 @@
*
* 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);
doAnswer(
new Answer<Object>() {
public SoftApManager answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
assertEquals(mNMService, (INetworkManagementService) args[0]);
mSoftApListener = (SoftApManager.Listener) args[1];
- assertEquals(mApInterface, (IApInterface) args[2]);
- assertEquals(wifiConfig, (WifiConfiguration) args[3]);
+ assertEquals(softApConfig, (SoftApModeConfiguration) args[2]);
return mSoftApManager;
}
}).when(mWifiInjector).makeSoftApManager(any(INetworkManagementService.class),
any(SoftApManager.Listener.class),
- any(IApInterface.class),
any());
- mWifiStateMachinePrime.enterSoftAPMode(wifiConfig);
+ mWifiStateMachinePrime.enterSoftAPMode(softApConfig);
mLooper.dispatchAll();
Log.e("WifiStateMachinePrimeTest", "check fromState: " + fromState);
if (!fromState.equals(WIFI_DISABLED_STATE_STRING)) {
- verify(mWificond).tearDownInterfaces();
+ verifyCleanupCalled();
}
assertEquals(SOFT_AP_MODE_ACTIVE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
verify(mSoftApManager).start();
}
+ private void verifyCleanupCalled() {
+ // for now, this is a single call, but make a helper to avoid adding any additional cleanup
+ // checks
+ verify(mWifiNative, atLeastOnce()).tearDown();
+ }
+
/**
- * Test that when a new instance of WifiStateMachinePrime is created, any existing interfaces in
- * the retrieved Wificond instance are cleaned up.
+ * Test that when a new instance of WifiStateMachinePrime is created, any existing
+ * resources in WifiNative are cleaned up.
* Expectations: When the new WifiStateMachinePrime instance is created a call to
- * Wificond.tearDownInterfaces() is made.
+ * WifiNative.tearDown() is made.
*/
@Test
- public void testWificondExistsOnStartup() throws Exception {
- when(mWifiInjector.makeWificond()).thenReturn(mWificond);
+ public void testCleanupOnStart() throws Exception {
WifiStateMachinePrime testWifiStateMachinePrime =
- new WifiStateMachinePrime(mWifiInjector, mLooper.getLooper(), mNMService);
- verify(mWificond).tearDownInterfaces();
+ new WifiStateMachinePrime(mWifiInjector, mLooper.getLooper(),
+ mWifiNative, mNMService);
+ verifyCleanupCalled();
}
/**
@@ -150,12 +156,10 @@
/**
* Test that WifiStateMachinePrime properly enters the SoftApModeActiveState from another state.
- * Expectations: When going from one state to another, any interfaces that are still up are torn
- * down.
+ * Expectations: When going from one state to another, cleanup will be called
*/
@Test
public void testEnterSoftApModeFromDifferentState() throws Exception {
- when(mWifiInjector.makeWificond()).thenReturn(mWificond);
mWifiStateMachinePrime.enterClientMode();
mLooper.dispatchAll();
assertEquals(CLIENT_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
@@ -172,7 +176,7 @@
mWifiStateMachinePrime.disableWifi();
mLooper.dispatchAll();
verify(mSoftApManager).stop();
- verify(mWificond).tearDownInterfaces();
+ verifyCleanupCalled();
assertEquals(WIFI_DISABLED_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
}
@@ -181,15 +185,15 @@
*/
@Test
public void testDisableWifiFromSoftApModeState() throws Exception {
- // Use a failure getting wificond to stay in the SoftAPModeState
- when(mWifiInjector.makeWificond()).thenReturn(null);
- mWifiStateMachinePrime.enterSoftAPMode(null);
+ enterSoftApActiveMode();
+ // now inject failure through the SoftApManager.Listener
+ mSoftApListener.onStateChanged(WifiManager.WIFI_AP_STATE_FAILED, 0);
mLooper.dispatchAll();
assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
mWifiStateMachinePrime.disableWifi();
mLooper.dispatchAll();
- // mWificond will be null due to this test, no call to tearDownInterfaces here.
+ verifyCleanupCalled();
assertEquals(WIFI_DISABLED_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
}
@@ -205,51 +209,24 @@
mWifiStateMachinePrime.enterClientMode();
mLooper.dispatchAll();
verify(mSoftApManager).stop();
- verify(mWificond).tearDownInterfaces();
+ verifyCleanupCalled();
assertEquals(CLIENT_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
}
/**
- * Test that we do not attempt to enter SoftApModeActiveState when we cannot get a reference to
- * wificond.
- * Expectations: After a failed attempt to get wificond from WifiInjector, we should remain in
- * the SoftApModeState.
- */
- @Test
- public void testWificondNullWhenSwitchingToApMode() throws Exception {
- when(mWifiInjector.makeWificond()).thenReturn(null);
- mWifiStateMachinePrime.enterSoftAPMode(null);
- mLooper.dispatchAll();
- assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
- }
-
- /**
- * Test that we do not attempt to enter SoftApModeActiveState when we cannot get an ApInterface
- * from wificond.
- * Expectations: After a failed attempt to get an ApInterface from WifiInjector, we should
- * remain in the SoftApModeState.
- */
- @Test
- public void testAPInterfaceFailedWhenSwitchingToApMode() throws Exception {
- when(mWifiInjector.makeWificond()).thenReturn(mWificond);
- when(mWificond.createApInterface()).thenReturn(null);
- mWifiStateMachinePrime.enterSoftAPMode(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);
+ enterSoftApActiveMode();
+ // now inject failure through the SoftApManager.Listener
+ mSoftApListener.onStateChanged(WifiManager.WIFI_AP_STATE_FAILED, 0);
mLooper.dispatchAll();
assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
+ // clear the first call to start SoftApManager
+ reset(mSoftApManager);
enterSoftApActiveMode();
}
@@ -294,7 +271,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,86 +286,50 @@
*/
@Test
public void testNullConfigIsPassedToWifiInjector() throws Exception {
- enterSoftApActiveMode(null);
+ enterSoftApActiveMode();
}
/**
- * Test that the proper config is used if a prior attempt fails without using the config.
- * Expectations: A call to start softap with a null config fails, but a second call has a set
- * config - this second call should use the correct config.
- */
- @Test
- public void testNullConfigFailsSecondCallWithConfigSuccessful() throws Exception {
- when(mWifiInjector.makeWificond()).thenReturn(mWificond);
- when(mWificond.createApInterface()).thenReturn(null);
- mWifiStateMachinePrime.enterSoftAPMode(null);
- mLooper.dispatchAll();
- assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
- WifiConfiguration config = new WifiConfiguration();
- config.SSID = "ThisIsAConfig";
- enterSoftApActiveMode(config);
- }
-
- /**
- * Test that a failed call to start softap with a valid config has the config saved for future
- * calls to enable softap.
- *
- * Expectations: A call to start SoftAPMode with a config should write out the config if we
- * did not create a SoftApManager.
- */
- @Test
- public void testValidConfigIsSavedOnFailureToStart() throws Exception {
- when(mWifiInjector.makeWificond()).thenReturn(null);
- when(mWifiInjector.getWifiApConfigStore()).thenReturn(mWifiApConfigStore);
- WifiConfiguration config = new WifiConfiguration();
- config.SSID = "ThisIsAConfig";
- mWifiStateMachinePrime.enterSoftAPMode(config);
- mLooper.dispatchAll();
- assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
- verify(mWifiApConfigStore).setApConfiguration(eq(config));
- }
-
- /**
- * Thest that two calls to switch to SoftAPMode in succession ends up with the correct config.
+ * Test that two calls to switch to SoftAPMode in succession ends up with the correct config.
*
* Expectation: we should end up in SoftAPMode state configured with the second config.
*/
@Test
public void testStartSoftApModeTwiceWithTwoConfigs() throws Exception {
- when(mWifiInjector.makeWificond()).thenReturn(mWificond);
- when(mWificond.createApInterface()).thenReturn(mApInterface);
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)))
+ eq(softApConfig1)))
.thenReturn(mSoftApManager);
when(mWifiInjector.makeSoftApManager(any(INetworkManagementService.class),
any(SoftApManager.Listener.class),
- any(IApInterface.class),
- eq(config2)))
+ 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());
}
/**
* Test that we safely disable wifi if it is already disabled.
- * Expectations: We should not interact with wificond since we should have already cleaned up
+ * Expectations: We should not interact with WifiNative since we should have already cleaned up
* everything.
*/
@Test
public void disableWifiWhenAlreadyOff() throws Exception {
- verifyNoMoreInteractions(mWificond);
+ verifyNoMoreInteractions(mWifiNative);
mWifiStateMachinePrime.disableWifi();
}
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java b/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
index 090224e..7e2a17b 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
@@ -16,18 +16,6 @@
package com.android.server.wifi;
-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 com.android.server.wifi.LocalOnlyHotspotRequestInfo.HOTSPOT_NO_ERROR;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
@@ -52,7 +40,6 @@
import android.net.NetworkRequest;
import android.net.dhcp.DhcpClient;
import android.net.ip.IpClient;
-import android.net.wifi.IApInterface;
import android.net.wifi.IClientInterface;
import android.net.wifi.IWificond;
import android.net.wifi.ScanResult;
@@ -63,6 +50,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 +69,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,8 +90,10 @@
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;
+import com.android.server.wifi.util.WifiPermissionsWrapper;
import org.junit.After;
import org.junit.Before;
@@ -150,6 +140,7 @@
private static final int WPS_FRAMEWORK_NETWORK_ID = 10;
private static final String DEFAULT_TEST_SSID = "\"GoogleGuest\"";
private static final String OP_PACKAGE_NAME = "com.xxx";
+ private static final int TEST_UID = Process.SYSTEM_UID + 1000;
private long mBinderToken;
@@ -334,6 +325,7 @@
IpClient.Callback mIpClientCallback;
PhoneStateListener mPhoneStateListener;
NetworkRequest mDefaultNetworkRequest;
+ OsuProvider mOsuProvider;
final ArgumentCaptor<SoftApManager.Listener> mSoftApManagerListenerCaptor =
ArgumentCaptor.forClass(SoftApManager.Listener.class);
@@ -350,10 +342,7 @@
@Mock PropertyService mPropertyService;
@Mock BuildProperties mBuildProperties;
@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 +359,10 @@
@Mock ScanDetailCache mScanDetailCache;
@Mock BaseWifiDiagnostics mWifiDiagnostics;
@Mock ConnectivityManager mConnectivityManager;
+ @Mock IProvisioningCallback mProvisioningCallback;
+ @Mock HandlerThread mWifiServiceHandlerThread;
+ @Mock WifiPermissionsWrapper mWifiPermissionsWrapper;
+ @Mock WakeupController mWakeupController;
public WifiStateMachineTest() throws Exception {
}
@@ -400,10 +393,10 @@
when(mWifiInjector.getWifiScanner()).thenReturn(mWifiScanner);
when(mWifiInjector.makeWifiConnectivityManager(any(WifiInfo.class), anyBoolean()))
.thenReturn(mWifiConnectivityManager);
- when(mWifiInjector.makeSoftApManager(any(INetworkManagementService.class),
- mSoftApManagerListenerCaptor.capture(), any(IApInterface.class),
- any(WifiConfiguration.class)))
- .thenReturn(mSoftApManager);
+ //when(mWifiInjector.makeSoftApManager(any(INetworkManagementService.class),
+ // mSoftApManagerListenerCaptor.capture(),
+ // any(SoftApModeConfiguration.class)))
+ // .thenReturn(mSoftApManager);
when(mWifiInjector.getPasspointManager()).thenReturn(mPasspointManager);
when(mWifiInjector.getWifiStateTracker()).thenReturn(mWifiStateTracker);
when(mWifiInjector.getWifiMonitor()).thenReturn(mWifiMonitor);
@@ -412,17 +405,23 @@
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(mWifiInjector.getWifiPermissionsWrapper()).thenReturn(mWifiPermissionsWrapper);
+ when(mWifiInjector.getWakeupController()).thenReturn(mWakeupController);
- when(mWifiNative.setupForClientMode())
+ when(mWifiNative.setupForClientMode(WIFI_IFACE_NAME))
.thenReturn(Pair.create(WifiNative.SETUP_SUCCESS, mClientInterface));
- when(mWifiNative.setupForSoftApMode())
- .thenReturn(Pair.create(WifiNative.SETUP_SUCCESS, mApInterface));
- when(mApInterface.getInterfaceName()).thenReturn(WIFI_IFACE_NAME);
+ //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 +447,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 {
@@ -459,7 +455,11 @@
}).when(mTelephonyManager).listen(any(PhoneStateListener.class), anyInt());
when(mWifiPermissionsUtil.checkNetworkSettingsPermission(anyInt())).thenReturn(true);
+ when(mWifiPermissionsWrapper.getLocalMacAddressPermission(anyInt()))
+ .thenReturn(PackageManager.PERMISSION_DENIED);
initializeWsm();
+
+ mOsuProvider = PasspointProvisioningTestUtil.generateOsuProvider(true);
}
private void registerAsyncChannel(Consumer<AsyncChannel> consumer, Messenger messenger) {
@@ -563,21 +563,6 @@
assertEquals("DisconnectedState", getCurrentState().getName());
}
- 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);
- }
-
private void loadComponentsInApMode(int mode) throws Exception {
SoftApModeConfiguration config = new SoftApModeConfiguration(mode, new WifiConfiguration());
mWsm.setHostApRunning(config, true);
@@ -585,33 +570,24 @@
assertEquals("SoftApState", getCurrentState().getName());
- verify(mWifiNative).setupForSoftApMode();
- verify(mSoftApManager).start();
+ verify(mWifiNative, never()).setupForSoftApMode(WIFI_IFACE_NAME);
+ verify(mSoftApManager, never()).start();
+ }
- // reset expectations for mContext due to previously sent AP broadcast
- reset(mContext);
+ private void setupMockWpsPbc() throws Exception {
+ loadComponentsInStaMode();
+ mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
+ mLooper.dispatchAll();
+ assertEquals("DisconnectedState", getCurrentState().getName());
- // get the SoftApManager.Listener and trigger some updates
- SoftApManager.Listener listener = mSoftApManagerListenerCaptor.getValue();
- listener.onStateChanged(WIFI_AP_STATE_ENABLING, 0);
- listener.onStateChanged(WIFI_AP_STATE_ENABLED, 0);
- listener.onStateChanged(WIFI_AP_STATE_DISABLING, 0);
- // note, this will trigger a mode change when TestLooper is dispatched
- listener.onStateChanged(WIFI_AP_STATE_DISABLED, 0);
-
- ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
- verify(mContext, times(4))
- .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, 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 +616,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 +935,7 @@
mWsm.sendMessage(WifiMonitor.SUP_CONNECTION_EVENT);
mLooper.dispatchAll();
- verify(mWifiNative).setupForClientMode();
+ verify(mWifiNative).setupForClientMode(WIFI_IFACE_NAME);
verify(mWifiLastResortWatchdog).clearAllFailureCounts();
}
@@ -1087,7 +1062,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 +1218,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 +1231,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 +1751,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 +1810,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 +1868,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 +1895,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 +1907,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 +1919,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 +1933,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 +2025,7 @@
mWsm.sendMessage(WifiMonitor.NETWORK_CONNECTION_EVENT, 0, 0, null);
mLooper.dispatchAll();
+ verify(mWifiMetrics).incrementWpsSuccessCount();
assertEquals("ObtainingIpState", getCurrentState().getName());
verifyMocksForWpsNetworkMigration();
}
@@ -2030,6 +2047,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 +2081,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();
@@ -2141,6 +2159,16 @@
assertEquals(sBSSID1, wifiInfo.getBSSID());
assertEquals(sFreq1, wifiInfo.getFrequency());
assertEquals(SupplicantState.COMPLETED, wifiInfo.getSupplicantState());
+
+ mWsm.sendMessage(WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, 0, 0,
+ new StateChangeResult(0, sWifiSsid, sBSSID1, SupplicantState.DISCONNECTED));
+ mLooper.dispatchAll();
+
+ wifiInfo = mWsm.getWifiInfo();
+ assertEquals(null, wifiInfo.getBSSID());
+ assertEquals(WifiSsid.NONE, wifiInfo.getSSID());
+ assertEquals(WifiConfiguration.INVALID_NETWORK_ID, wifiInfo.getNetworkId());
+ assertEquals(SupplicantState.DISCONNECTED, wifiInfo.getSupplicantState());
}
/**
@@ -2236,56 +2264,29 @@
}
/**
- * Test that the process uid has full wifiInfo access.
- * Also tests that {@link WifiStateMachine#syncRequestConnectionInfo(String)} always
- * returns a copy of WifiInfo.
- */
- @Test
- public void testConnectedIdsAreVisibleFromOwnUid() throws Exception {
- assertEquals(Process.myUid(), Binder.getCallingUid());
- WifiInfo wifiInfo = mWsm.getWifiInfo();
- wifiInfo.setBSSID(sBSSID);
- wifiInfo.setSSID(WifiSsid.createFromAsciiEncoded(sSSID));
-
- connect();
- WifiInfo connectionInfo = mWsm.syncRequestConnectionInfo(mContext.getOpPackageName());
-
- assertNotEquals(wifiInfo, connectionInfo);
- assertEquals(wifiInfo.getSSID(), connectionInfo.getSSID());
- assertEquals(wifiInfo.getBSSID(), connectionInfo.getBSSID());
- }
-
- /**
* Test that connected SSID and BSSID are not exposed to an app that does not have the
* appropriate permissions.
* Also tests that {@link WifiStateMachine#syncRequestConnectionInfo(String)} always
* returns a copy of WifiInfo.
*/
@Test
- public void testConnectedIdsAreHiddenFromRandomApp() throws Exception {
- int actualUid = Binder.getCallingUid();
- int fakeUid = Process.myUid() + 100000;
- assertNotEquals(actualUid, fakeUid);
- BinderUtil.setUid(fakeUid);
- try {
- WifiInfo wifiInfo = mWsm.getWifiInfo();
+ public void testConnectedIdsAreHiddenFromAppWithoutPermission() throws Exception {
+ WifiInfo wifiInfo = mWsm.getWifiInfo();
- // Get into a connected state, with known BSSID and SSID
- connect();
- assertEquals(sBSSID, wifiInfo.getBSSID());
- assertEquals(sWifiSsid, wifiInfo.getWifiSsid());
+ // Get into a connected state, with known BSSID and SSID
+ connect();
+ assertEquals(sBSSID, wifiInfo.getBSSID());
+ assertEquals(sWifiSsid, wifiInfo.getWifiSsid());
- when(mWifiPermissionsUtil.canAccessFullConnectionInfo(any(), anyString(), eq(fakeUid),
- anyInt())).thenReturn(false);
+ when(mWifiPermissionsUtil.canAccessScanResults(anyString(), eq(TEST_UID), anyInt()))
+ .thenReturn(false);
- WifiInfo connectionInfo = mWsm.syncRequestConnectionInfo(mContext.getOpPackageName());
+ WifiInfo connectionInfo = mWsm.syncRequestConnectionInfo(mContext.getOpPackageName(),
+ TEST_UID);
- assertNotEquals(wifiInfo, connectionInfo);
- assertEquals(WifiSsid.NONE, connectionInfo.getSSID());
- assertEquals(WifiInfo.DEFAULT_MAC_ADDRESS, connectionInfo.getBSSID());
- } finally {
- BinderUtil.setUid(actualUid);
- }
+ assertNotEquals(wifiInfo, connectionInfo);
+ assertEquals(WifiSsid.NONE, connectionInfo.getSSID());
+ assertEquals(WifiInfo.DEFAULT_MAC_ADDRESS, connectionInfo.getBSSID());
}
/**
@@ -2296,29 +2297,48 @@
*/
@Test
public void testConnectedIdsAreHiddenOnSecurityException() throws Exception {
- int actualUid = Binder.getCallingUid();
- int fakeUid = Process.myUid() + 100000;
- assertNotEquals(actualUid, fakeUid);
- BinderUtil.setUid(fakeUid);
- try {
- WifiInfo wifiInfo = mWsm.getWifiInfo();
+ WifiInfo wifiInfo = mWsm.getWifiInfo();
- // Get into a connected state, with known BSSID and SSID
- connect();
- assertEquals(sBSSID, wifiInfo.getBSSID());
- assertEquals(sWifiSsid, wifiInfo.getWifiSsid());
+ // Get into a connected state, with known BSSID and SSID
+ connect();
+ assertEquals(sBSSID, wifiInfo.getBSSID());
+ assertEquals(sWifiSsid, wifiInfo.getWifiSsid());
- when(mWifiPermissionsUtil.canAccessFullConnectionInfo(any(), anyString(), eq(fakeUid),
- anyInt())).thenThrow(new SecurityException());
+ when(mWifiPermissionsUtil.canAccessScanResults(anyString(), eq(TEST_UID), anyInt()))
+ .thenThrow(new SecurityException());
- WifiInfo connectionInfo = mWsm.syncRequestConnectionInfo(mContext.getOpPackageName());
+ WifiInfo connectionInfo = mWsm.syncRequestConnectionInfo(mContext.getOpPackageName(),
+ TEST_UID);
- assertNotEquals(wifiInfo, connectionInfo);
- assertEquals(WifiSsid.NONE, connectionInfo.getSSID());
- assertEquals(WifiInfo.DEFAULT_MAC_ADDRESS, connectionInfo.getBSSID());
- } finally {
- BinderUtil.setUid(actualUid);
- }
+ assertNotEquals(wifiInfo, connectionInfo);
+ assertEquals(WifiSsid.NONE, connectionInfo.getSSID());
+ assertEquals(WifiInfo.DEFAULT_MAC_ADDRESS, connectionInfo.getBSSID());
+ }
+
+ /**
+ * Test that connected SSID and BSSID are exposed to system server
+ */
+ @Test
+ public void testConnectedIdsAreVisibleFromSystemServer() throws Exception {
+ when(mWifiPermissionsWrapper.getLocalMacAddressPermission(anyInt()))
+ .thenReturn(PackageManager.PERMISSION_GRANTED);
+
+ WifiInfo wifiInfo = mWsm.getWifiInfo();
+ // Get into a connected state, with known BSSID and SSID
+ connect();
+ assertEquals(sBSSID, wifiInfo.getBSSID());
+ assertEquals(sWifiSsid, wifiInfo.getWifiSsid());
+
+ when(mWifiPermissionsUtil.canAccessScanResults(anyString(), eq(TEST_UID), anyInt()))
+ .thenReturn(true);
+
+ WifiInfo connectionInfo = mWsm.syncRequestConnectionInfo(mContext.getOpPackageName(),
+ TEST_UID);
+
+ assertNotEquals(wifiInfo, connectionInfo);
+ assertEquals(wifiInfo.getSSID(), connectionInfo.getSSID());
+ assertEquals(wifiInfo.getBSSID(), connectionInfo.getBSSID());
+ assertEquals(wifiInfo.getMacAddress(), connectionInfo.getMacAddress());
}
/**
@@ -2327,30 +2347,24 @@
*/
@Test
public void testConnectedIdsAreVisibleFromPermittedApp() throws Exception {
- int actualUid = Binder.getCallingUid();
- int fakeUid = Process.myUid() + 100000;
- BinderUtil.setUid(fakeUid);
- try {
- WifiInfo wifiInfo = mWsm.getWifiInfo();
+ WifiInfo wifiInfo = mWsm.getWifiInfo();
- // Get into a connected state, with known BSSID and SSID
- connect();
- assertEquals(sBSSID, wifiInfo.getBSSID());
- assertEquals(sWifiSsid, wifiInfo.getWifiSsid());
+ // Get into a connected state, with known BSSID and SSID
+ connect();
+ assertEquals(sBSSID, wifiInfo.getBSSID());
+ assertEquals(sWifiSsid, wifiInfo.getWifiSsid());
- when(mWifiPermissionsUtil.canAccessFullConnectionInfo(any(), anyString(), eq(fakeUid),
- anyInt())).thenReturn(true);
+ when(mWifiPermissionsUtil.canAccessScanResults(anyString(), eq(TEST_UID), anyInt()))
+ .thenReturn(true);
- WifiInfo connectionInfo = mWsm.syncRequestConnectionInfo(mContext.getOpPackageName());
+ WifiInfo connectionInfo = mWsm.syncRequestConnectionInfo(mContext.getOpPackageName(),
+ TEST_UID);
- assertNotEquals(wifiInfo, connectionInfo);
- assertEquals(wifiInfo.getSSID(), connectionInfo.getSSID());
- assertEquals(wifiInfo.getBSSID(), connectionInfo.getBSSID());
- // Access to our MAC address uses a different permission, make sure it is not granted
- assertEquals(WifiInfo.DEFAULT_MAC_ADDRESS, connectionInfo.getMacAddress());
- } finally {
- BinderUtil.setUid(actualUid);
- }
+ assertNotEquals(wifiInfo, connectionInfo);
+ assertEquals(wifiInfo.getSSID(), connectionInfo.getSSID());
+ assertEquals(wifiInfo.getBSSID(), connectionInfo.getBSSID());
+ // Access to our MAC address uses a different permission, make sure it is not granted
+ assertEquals(WifiInfo.DEFAULT_MAC_ADDRESS, connectionInfo.getMacAddress());
}
/**
@@ -2404,6 +2418,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);
}
@@ -2423,45 +2439,11 @@
}
/**
- * Test that failure to start HAL in AP mode increments the corresponding metrics.
- */
- @Test
- public void testSetupForSoftApModeHalFailureIncrementsMetrics() throws Exception {
- when(mWifiNative.setupForSoftApMode())
- .thenReturn(Pair.create(WifiNative.SETUP_FAILURE_HAL, null));
-
- SoftApModeConfiguration config = new SoftApModeConfiguration(
- WifiManager.IFACE_IP_MODE_TETHERED, new WifiConfiguration());
- mWsm.setHostApRunning(config, true);
- mLooper.dispatchAll();
-
- verify(mWifiNative).setupForSoftApMode();
- verify(mWifiMetrics).incrementNumWifiOnFailureDueToHal();
- }
-
- /**
- * Test that failure to start HAL in AP mode increments the corresponding metrics.
- */
- @Test
- public void testSetupForSoftApModeWificondFailureIncrementsMetrics() throws Exception {
- when(mWifiNative.setupForSoftApMode())
- .thenReturn(Pair.create(WifiNative.SETUP_FAILURE_WIFICOND, null));
-
- SoftApModeConfiguration config = new SoftApModeConfiguration(
- WifiManager.IFACE_IP_MODE_TETHERED, new WifiConfiguration());
- mWsm.setHostApRunning(config, true);
- mLooper.dispatchAll();
-
- verify(mWifiNative).setupForSoftApMode();
- verify(mWifiMetrics).incrementNumWifiOnFailureDueToWificond();
- }
-
- /**
* Test that failure to start HAL in client mode increments the corresponding metrics.
*/
@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 +2452,7 @@
mWsm.sendMessage(WifiMonitor.SUP_CONNECTION_EVENT);
mLooper.dispatchAll();
- verify(mWifiNative).setupForClientMode();
+ verify(mWifiNative).setupForClientMode(WIFI_IFACE_NAME);
verify(mWifiMetrics).incrementNumWifiOnFailureDueToHal();
}
@@ -2479,7 +2461,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 +2470,7 @@
mWsm.sendMessage(WifiMonitor.SUP_CONNECTION_EVENT);
mLooper.dispatchAll();
- verify(mWifiNative).setupForClientMode();
+ verify(mWifiNative).setupForClientMode(WIFI_IFACE_NAME);
verify(mWifiMetrics).incrementNumWifiOnFailureDueToWificond();
}
@@ -2773,4 +2755,49 @@
currentConfig.networkId = lastSelectedNetworkId - 1;
assertFalse(mWsm.shouldEvaluateWhetherToSendExplicitlySelected(currentConfig));
}
+
+ /**
+ * Verify that WSM dump includes WakeupController.
+ */
+ @Test
+ public void testDumpShouldDumpWakeupController() {
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ PrintWriter writer = new PrintWriter(stream);
+ mWsm.dump(null, writer, null);
+ verify(mWakeupController).dump(null, writer, null);
+ }
+
+ /**
+ * Verify that entering and exiting scan mode state correctly triggers Wakeup lifecycle events.
+ */
+ @Test
+ public void verifyScanModeStateTransitionsTriggerWakeupLifecycleEvents() throws Exception {
+ loadComponentsInStaMode();
+
+ // enter scan mode
+ mWsm.setOperationalMode(WifiStateMachine.SCAN_ONLY_MODE);
+ mLooper.dispatchAll();
+
+ // exit scan mode
+ mWsm.setOperationalMode(WifiStateMachine.DISABLED_MODE);
+ mLooper.dispatchAll();
+
+ InOrder inOrder = inOrder(mWakeupController);
+ inOrder.verify(mWakeupController).start();
+ inOrder.verify(mWakeupController).stop();
+ }
+
+ /**
+ * Verify that entering connect mode state resets WakeupController events.
+ */
+ @Test
+ public void verifyConnectModeStateTransitionsTriggerWakeupLifecycleEvents() throws Exception {
+ loadComponentsInStaMode();
+
+ // enter connect mode
+ mWsm.setOperationalMode(WifiStateMachine.CONNECT_MODE);
+ mLooper.dispatchAll();
+
+ verify(mWakeupController).reset();
+ }
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiVendorHalTest.java b/tests/wifitests/src/com/android/server/wifi/WifiVendorHalTest.java
index 84de9d2..9830b91 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;
@@ -51,22 +77,20 @@
import android.net.apf.ApfCapabilities;
import android.net.wifi.RttManager;
import android.net.wifi.ScanResult;
-import android.net.wifi.WifiLinkLayerStats;
import android.net.wifi.WifiManager;
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;
import android.util.Pair;
import com.android.server.connectivity.KeepalivePacketData;
+import com.android.server.wifi.HalDeviceManager.InterfaceDestroyedListener;
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;
@@ -167,14 +192,14 @@
mHalDeviceManagerStatusCallbacks.onStatusChanged();
}
}).when(mHalDeviceManager).stop();
- when(mHalDeviceManager.createStaIface(eq(null), eq(null)))
+ when(mHalDeviceManager.createStaIface(any(), eq(null)))
.thenReturn(mIWifiStaIface);
- when(mHalDeviceManager.createApIface(eq(null), eq(null)))
+ when(mHalDeviceManager.createApIface(any(), 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,54 +240,55 @@
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).createStaIface(any(), 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));
verify(mIWifiChip).registerEventCallback(any(IWifiChipEventCallback.class));
- verify(mHalDeviceManager, never()).createApIface(eq(null), eq(null));
+ verify(mHalDeviceManager, never()).createApIface(any(), eq(null));
}
/**
* 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();
- verify(mHalDeviceManager).createApIface(eq(null), eq(null));
+ verify(mHalDeviceManager).createApIface(any(), eq(null));
verify(mHalDeviceManager).getChip(eq(mIWifiApIface));
verify(mHalDeviceManager).isReady();
verify(mHalDeviceManager).isStarted();
- verify(mHalDeviceManager, never()).createStaIface(eq(null), eq(null));
- verify(mHalDeviceManager, never()).createRttController(any(IWifiIface.class));
+ verify(mHalDeviceManager, never()).createStaIface(any(), eq(null));
+ 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,140 +299,140 @@
return false;
}
}).when(mHalDeviceManager).start();
- assertFalse(mWifiVendorHal.startVendorHal(true));
+ assertFalse(mWifiVendorHal.startVendorHalSta());
assertFalse(mWifiVendorHal.isHalStarted());
verify(mHalDeviceManager).start();
- verify(mHalDeviceManager, never()).createStaIface(eq(null), eq(null));
- verify(mHalDeviceManager, never()).createApIface(eq(null), eq(null));
+ verify(mHalDeviceManager, never()).createStaIface(any(), eq(null));
+ verify(mHalDeviceManager, never()).createApIface(any(), 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));
+ when(mHalDeviceManager.createStaIface(any(), eq(null))).thenReturn(null);
+ assertFalse(mWifiVendorHal.startVendorHalSta());
assertFalse(mWifiVendorHal.isHalStarted());
verify(mHalDeviceManager).start();
- verify(mHalDeviceManager).createStaIface(eq(null), eq(null));
+ verify(mHalDeviceManager).createStaIface(any(), eq(null));
verify(mHalDeviceManager).stop();
- verify(mHalDeviceManager, never()).createApIface(eq(null), eq(null));
+ verify(mHalDeviceManager, never()).createApIface(any(), 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).createStaIface(any(), eq(null));
+ verify(mHalDeviceManager).createRttController();
verify(mHalDeviceManager).stop();
verify(mIWifiStaIface).registerEventCallback(any(IWifiStaIfaceEventCallback.class));
- verify(mHalDeviceManager, never()).createApIface(eq(null), eq(null));
+ verify(mHalDeviceManager, never()).createApIface(any(), eq(null));
verify(mHalDeviceManager, never()).getChip(any(IWifiIface.class));
}
/**
* 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).createStaIface(any(), eq(null));
+ verify(mHalDeviceManager).createRttController();
verify(mHalDeviceManager).getChip(any(IWifiIface.class));
verify(mHalDeviceManager).stop();
verify(mIWifiStaIface).registerEventCallback(any(IWifiStaIfaceEventCallback.class));
- verify(mHalDeviceManager, never()).createApIface(eq(null), eq(null));
+ verify(mHalDeviceManager, never()).createApIface(any(), eq(null));
}
/**
* 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();
- verify(mHalDeviceManager).createStaIface(eq(null), eq(null));
+ verify(mHalDeviceManager).createStaIface(any(), eq(null));
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));
+ verify(mHalDeviceManager, never()).createApIface(any(), 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).createStaIface(any(), eq(null));
+ verify(mHalDeviceManager).createRttController();
verify(mHalDeviceManager).getChip(any(IWifiIface.class));
verify(mHalDeviceManager).stop();
verify(mIWifiStaIface).registerEventCallback(any(IWifiStaIfaceEventCallback.class));
verify(mIWifiChip).registerEventCallback(any(IWifiChipEventCallback.class));
- verify(mHalDeviceManager, never()).createApIface(eq(null), eq(null));
+ verify(mHalDeviceManager, never()).createApIface(any(), eq(null));
}
/**
- * 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));
+ when(mHalDeviceManager.createApIface(any(), eq(null))).thenReturn(null);
+ assertFalse(mWifiVendorHal.startVendorHalAp());
assertFalse(mWifiVendorHal.isHalStarted());
verify(mHalDeviceManager).start();
- verify(mHalDeviceManager).createApIface(eq(null), eq(null));
+ verify(mHalDeviceManager).createApIface(any(), eq(null));
verify(mHalDeviceManager).stop();
- verify(mHalDeviceManager, never()).createStaIface(eq(null), eq(null));
+ verify(mHalDeviceManager, never()).createStaIface(any(), 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();
@@ -410,13 +449,13 @@
verify(mHalDeviceManager).start();
verify(mHalDeviceManager).stop();
- verify(mHalDeviceManager).createStaIface(eq(null), eq(null));
+ verify(mHalDeviceManager).createStaIface(any(), 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();
- verify(mHalDeviceManager, never()).createApIface(eq(null), eq(null));
+ verify(mHalDeviceManager, never()).createApIface(any(), eq(null));
}
/**
@@ -425,7 +464,7 @@
*/
@Test
public void testStopHalInApMode() {
- assertTrue(mWifiVendorHal.startVendorHal(false));
+ assertTrue(mWifiVendorHal.startVendorHalAp());
assertTrue(mWifiVendorHal.isHalStarted());
mWifiVendorHal.stopVendorHal();
@@ -433,13 +472,75 @@
verify(mHalDeviceManager).start();
verify(mHalDeviceManager).stop();
- verify(mHalDeviceManager).createApIface(eq(null), eq(null));
+ verify(mHalDeviceManager).createApIface(any(), eq(null));
verify(mHalDeviceManager).getChip(eq(mIWifiApIface));
verify(mHalDeviceManager, times(2)).isReady();
verify(mHalDeviceManager, times(2)).isStarted();
- verify(mHalDeviceManager, never()).createStaIface(eq(null), eq(null));
- verify(mHalDeviceManager, never()).createRttController(any(IWifiIface.class));
+ verify(mHalDeviceManager, never()).createStaIface(any(), eq(null));
+ verify(mHalDeviceManager, never()).createRttController();
+ }
+
+ /**
+ * Tests the handling of interface destroyed callback from HalDeviceManager.
+ */
+ @Test
+ public void testStaInterfaceDestroyedHandling() throws Exception {
+ ArgumentCaptor<InterfaceDestroyedListener> internalListenerCaptor =
+ ArgumentCaptor.forClass(InterfaceDestroyedListener.class);
+ InterfaceDestroyedListener externalLister = mock(InterfaceDestroyedListener.class);
+
+ assertTrue(mWifiVendorHal.startVendorHal());
+ assertNotNull(mWifiVendorHal.createStaIface(externalLister));
+ assertTrue(mWifiVendorHal.isHalStarted());
+
+ verify(mHalDeviceManager).start();
+ verify(mHalDeviceManager).createStaIface(internalListenerCaptor.capture(), eq(null));
+ verify(mHalDeviceManager).getChip(eq(mIWifiStaIface));
+ verify(mHalDeviceManager).createRttController();
+ verify(mHalDeviceManager).isReady();
+ verify(mHalDeviceManager).isStarted();
+ verify(mIWifiStaIface).registerEventCallback(any(IWifiStaIfaceEventCallback.class));
+ verify(mIWifiChip).registerEventCallback(any(IWifiChipEventCallback.class));
+
+ // Now trigger the interface destroyed callback from HalDeviceManager and ensure the
+ // external listener is invoked and iface removed from internal database.
+ internalListenerCaptor.getValue().onDestroyed(TEST_IFACE_NAME);
+ verify(externalLister).onDestroyed(TEST_IFACE_NAME);
+
+ // This should fail now, since the interface was already destroyed.
+ assertFalse(mWifiVendorHal.removeStaIface(TEST_IFACE_NAME));
+ verify(mHalDeviceManager, never()).removeIface(any());
+ }
+
+ /**
+ * Tests the handling of interface destroyed callback from HalDeviceManager.
+ */
+ @Test
+ public void testApInterfaceDestroyedHandling() throws Exception {
+ ArgumentCaptor<InterfaceDestroyedListener> internalListenerCaptor =
+ ArgumentCaptor.forClass(InterfaceDestroyedListener.class);
+ InterfaceDestroyedListener externalLister = mock(InterfaceDestroyedListener.class);
+
+ assertTrue(mWifiVendorHal.startVendorHal());
+ assertNotNull(mWifiVendorHal.createApIface(externalLister));
+ assertTrue(mWifiVendorHal.isHalStarted());
+
+ verify(mHalDeviceManager).start();
+ verify(mHalDeviceManager).createApIface(internalListenerCaptor.capture(), eq(null));
+ verify(mHalDeviceManager).getChip(eq(mIWifiApIface));
+ verify(mHalDeviceManager).isReady();
+ verify(mHalDeviceManager).isStarted();
+ verify(mIWifiChip).registerEventCallback(any(IWifiChipEventCallback.class));
+
+ // Now trigger the interface destroyed callback from HalDeviceManager and ensure the
+ // external listener is invoked and iface removed from internal database.
+ internalListenerCaptor.getValue().onDestroyed(TEST_IFACE_NAME);
+ verify(externalLister).onDestroyed(TEST_IFACE_NAME);
+
+ // This should fail now, since the interface was already destroyed.
+ assertFalse(mWifiVendorHal.removeApIface(TEST_IFACE_NAME));
+ verify(mHalDeviceManager, never()).removeIface(any());
}
/**
@@ -449,7 +550,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 +560,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 +575,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 +605,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 +618,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 +664,7 @@
*/
@Test
public void testGetSupportedFeatures() throws Exception {
- assertTrue(mWifiVendorHal.startVendorHal(true));
+ assertTrue(mWifiVendorHal.startVendorHalSta());
int staIfaceHidlCaps = (
IWifiStaIface.StaIfaceCapabilityMask.BACKGROUND_SCAN
@@ -653,7 +697,7 @@
when(mHalDeviceManager.getSupportedIfaceTypes())
.thenReturn(halDeviceManagerSupportedIfaces);
- assertEquals(expectedFeatureSet, mWifiVendorHal.getSupportedFeatureSet());
+ assertEquals(expectedFeatureSet, mWifiVendorHal.getSupportedFeatureSet(TEST_IFACE_NAME));
}
/**
@@ -670,13 +714,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 +739,7 @@
assertTrue(mWifiVendorHal.startVendorHalAp());
assertTrue(mWifiVendorHal.isHalStarted());
- assertNull(mWifiVendorHal.getWifiLinkLayerStats());
+ assertNull(mWifiVendorHal.getWifiLinkLayerStats(TEST_IFACE_NAME));
verify(mHalDeviceManager).start();
@@ -722,13 +766,13 @@
randomizePacketStats(r, stats.iface.wmeVoPktStats);
randomizeRadioStats(r, stats.radios);
- stats.timeStampInMs = 42; // currently dropped in conversion
+ stats.timeStampInMs = r.nextLong() & 0xFFFFFFFFFFL;
- String expected = numbersOnly(stats.toString());
+ String expected = numbersOnly(stats.toString() + " ");
WifiLinkLayerStats converted = WifiVendorHal.frameworkFromHalLinkLayerStats(stats);
- String actual = numbersOnly(converted.toString());
+ String actual = numbersOnly(converted.toString() + " ");
// Do the required fixups to the both expected and actual
expected = rmValue(expected, stats.radios.get(0).rxTimeInMs);
@@ -736,7 +780,6 @@
actual = rmValue(actual, stats.radios.get(0).rxTimeInMs);
actual = rmValue(actual, stats.radios.get(0).onTimeInMsForScan);
- actual = actual + "42 ";
// The remaining fields should agree
assertEquals(expected, actual);
@@ -899,19 +942,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 +1001,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 +1027,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 +1056,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 +1070,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 +1096,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 +1143,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 +1170,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 +1187,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 +1207,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 +1324,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 +1357,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 +1400,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 +1441,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 +1484,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 +1506,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 +1517,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 +1529,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 +1549,7 @@
assertTrue(mWifiVendorHal.startVendorHalSta());
- assertFalse(mWifiVendorHal.configureNeighborDiscoveryOffload(true));
+ assertFalse(mWifiVendorHal.configureNeighborDiscoveryOffload(TEST_IFACE_NAME, true));
verify(mIWifiStaIface).enableNdOffload(eq(true));
}
@@ -1667,8 +1765,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 +1783,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 +1947,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 +1958,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 +1973,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 +1983,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 +1999,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(any(), 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(any(), 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(any(), 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(any(), 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 +2076,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..537845c 100644
--- a/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareDataPathStateManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareDataPathStateManagerTest.java
@@ -1213,12 +1213,12 @@
if (doPublish) {
sessionCaptor.getValue().publish(publishConfig, mockSessionCallback,
mMockLooperHandler);
- inOrderS.verify(mockAwareService).publish(eq(clientId), eq(publishConfig),
+ inOrderS.verify(mockAwareService).publish(any(), eq(clientId), eq(publishConfig),
sessionProxyCallback.capture());
} else {
sessionCaptor.getValue().subscribe(subscribeConfig, mockSessionCallback,
mMockLooperHandler);
- inOrderS.verify(mockAwareService).subscribe(eq(clientId), eq(subscribeConfig),
+ inOrderS.verify(mockAwareService).subscribe(any(), eq(clientId), eq(subscribeConfig),
sessionProxyCallback.capture());
}
sessionProxyCallback.getValue().onSessionStarted(sessionId);
@@ -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..56515ee 100644
--- a/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareNativeManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareNativeManagerTest.java
@@ -16,11 +16,12 @@
package com.android.server.wifi.aware;
-import static org.hamcrest.core.IsEqual.equalTo;
-import static org.hamcrest.core.IsNull.nullValue;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
@@ -28,6 +29,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 +51,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,89 +76,168 @@
mDut = new WifiAwareNativeManager(mWifiAwareStateManagerMock,
mHalDeviceManager, mWifiAwareNativeCallback);
- mDut.start();
+ mDut.start(mHandlerMock);
mInOrder = inOrder(mWifiAwareStateManagerMock, mHalDeviceManager);
+
+ // validate (and capture) that register manage status callback
+ mInOrder.verify(mHalDeviceManager).initialize();
+ mInOrder.verify(mHalDeviceManager).registerStatusListener(
+ mManagerStatusListenerCaptor.capture(), any());
}
/**
- * Test the control flow of the manager:
+ * Test the control flow of the manager when Aware isn't being actively used:
+ *
* 1. onStatusChange (ready/started)
- * 2. null NAN iface
- * 3. onAvailableForRequest
- * 4. non-null NAN iface -> enableUsage
- * 5. onStatusChange (!started) -> disableUsage
- * 6. onStatusChange (ready/started)
- * 7. non-null NAN iface -> enableUsage
- * 8. onDestroyed -> disableUsage
- * 9. onStatusChange (!started)
+ * 2. on available -> enableUsage
+ * 3. onStatusChange (!started) -> disableUsage
+ * 4. onStatusChange (ready/started) + available -> enableUsage
+ * 5. on not available -> disableUsage
+ *
+ * --> no interface creation at any point!
*/
@Test
- public void testControlFlow() {
- // configure HalDeviceManager as ready/wifi started
+ public void testControlFlowWithoutInterface() {
+ // configure HalDeviceManager as ready/wifi started (and to return an interface if
+ // requested)
when(mHalDeviceManager.isReady()).thenReturn(true);
when(mHalDeviceManager.isStarted()).thenReturn(true);
-
- // validate (and capture) that register manage status callback
- mInOrder.verify(mHalDeviceManager).registerStatusListener(
- mManagerStatusListenerCaptor.capture(), any());
-
- // 1 & 2 onStatusChange (ready/started): validate that trying to get a NAN interface
- // (make sure gets a NULL)
- when(mHalDeviceManager.createNanIface(any(), any())).thenReturn(null);
-
- mManagerStatusListenerCaptor.getValue().onStatusChanged();
- mInOrder.verify(mHalDeviceManager).registerInterfaceAvailableForRequestListener(
- eq(IfaceType.NAN), mAvailListenerCaptor.capture(), any());
- mAvailListenerCaptor.getValue().onAvailableForRequest();
-
- mInOrder.verify(mHalDeviceManager).createNanIface(
- mDestroyedListenerCaptor.capture(), any());
- collector.checkThat("null interface", mDut.getWifiNanIface(), nullValue());
-
- // 3 & 4 onAvailableForRequest + non-null return value: validate that enables usage
when(mHalDeviceManager.createNanIface(any(), any())).thenReturn(mWifiNanIfaceMock);
- mAvailListenerCaptor.getValue().onAvailableForRequest();
+ // 1. onStatusChange (ready/started)
+ mManagerStatusListenerCaptor.getValue().onStatusChanged();
+ mInOrder.verify(mHalDeviceManager).registerInterfaceAvailableForRequestListener(
+ eq(IfaceType.NAN), mAvailListenerCaptor.capture(), any(Handler.class));
- mInOrder.verify(mHalDeviceManager).createNanIface(
- mDestroyedListenerCaptor.capture(), any());
+ // 2. NAN is available -> enableUsage
+ mAvailListenerCaptor.getValue().onAvailabilityChanged(true);
mInOrder.verify(mWifiAwareStateManagerMock).enableUsage();
- collector.checkThat("non-null interface", mDut.getWifiNanIface(),
- equalTo(mWifiNanIfaceMock));
- // 5 onStatusChange (!started): disable usage
+ // 3. onStatusChange (not ready) -> disableUsage
when(mHalDeviceManager.isStarted()).thenReturn(false);
mManagerStatusListenerCaptor.getValue().onStatusChanged();
mInOrder.verify(mWifiAwareStateManagerMock).disableUsage();
- collector.checkThat("null interface", mDut.getWifiNanIface(), nullValue());
- // 6 & 7 onStatusChange (ready/started) + non-null NAN interface: enable usage
+ // 4. onStatusChange (ready/started) + available -> enableUsage
when(mHalDeviceManager.isStarted()).thenReturn(true);
mManagerStatusListenerCaptor.getValue().onStatusChanged();
mManagerStatusListenerCaptor.getValue().onStatusChanged();
mInOrder.verify(mHalDeviceManager).registerInterfaceAvailableForRequestListener(
- eq(IfaceType.NAN), mAvailListenerCaptor.capture(), any());
- mAvailListenerCaptor.getValue().onAvailableForRequest();
+ eq(IfaceType.NAN), mAvailListenerCaptor.capture(), any(Handler.class));
+ mAvailListenerCaptor.getValue().onAvailabilityChanged(true);
- mInOrder.verify(mHalDeviceManager).createNanIface(
- mDestroyedListenerCaptor.capture(), any());
mInOrder.verify(mWifiAwareStateManagerMock).enableUsage();
- collector.checkThat("non-null interface", mDut.getWifiNanIface(),
- equalTo(mWifiNanIfaceMock));
- // 8 onDestroyed: disable usage
- mDestroyedListenerCaptor.getValue().onDestroyed();
+ // 5. not available -> disableUsage
+ mAvailListenerCaptor.getValue().onAvailabilityChanged(false);
mInOrder.verify(mWifiAwareStateManagerMock).disableUsage();
- collector.checkThat("null interface", mDut.getWifiNanIface(), nullValue());
- // 9 onStatusChange (!started): nothing more happens
- when(mHalDeviceManager.isStarted()).thenReturn(false);
+ mInOrder.verify(mHalDeviceManager, never()).createNanIface(any(), any());
+ verifyNoMoreInteractions(mWifiAwareStateManagerMock);
+ assertNull("Interface non-null!", mDut.getWifiNanIface());
+ }
+
+ /**
+ * Test the control flow (and reference counting) of the manager when Aware is actively used and
+ * reference counted (i.e. irregular requests/releases).
+ */
+ @Test
+ public void testReferenceCounting() {
+ // configure HalDeviceManager as ready/wifi started (and to return an interface if
+ // requested)
+ when(mHalDeviceManager.isReady()).thenReturn(true);
+ when(mHalDeviceManager.isStarted()).thenReturn(true);
+ when(mHalDeviceManager.createNanIface(any(), any())).thenReturn(mWifiNanIfaceMock);
+
+ // 1. onStatusChange (ready/started)
mManagerStatusListenerCaptor.getValue().onStatusChanged();
+ mInOrder.verify(mHalDeviceManager).registerInterfaceAvailableForRequestListener(
+ eq(IfaceType.NAN), mAvailListenerCaptor.capture(), any(Handler.class));
+ assertNull("Interface non-null!", mDut.getWifiNanIface());
+ mAvailListenerCaptor.getValue().onAvailabilityChanged(true);
+ mInOrder.verify(mWifiAwareStateManagerMock).enableUsage();
+
+ // 2. request (interface obtained)
+ mDut.tryToGetAware();
+ mInOrder.verify(mHalDeviceManager).createNanIface(mDestroyedListenerCaptor.capture(),
+ any());
+ assertEquals("Interface mismatch", mWifiNanIfaceMock, mDut.getWifiNanIface());
+
+ // 3. release (interface released)
+ mDut.releaseAware();
+ mInOrder.verify(mHalDeviceManager).removeIface(mWifiNanIfaceMock);
+ assertNull("Interface non-null!", mDut.getWifiNanIface());
+
+ mDestroyedListenerCaptor.getValue().onDestroyed("nan0");
+
+ // 4. request (interface obtained)
+ mDut.tryToGetAware();
+ mInOrder.verify(mHalDeviceManager).createNanIface(mDestroyedListenerCaptor.capture(),
+ any());
+ assertEquals("Interface mismatch", mWifiNanIfaceMock, mDut.getWifiNanIface());
+
+ // 5. request (nop - already have interface)
+ mDut.tryToGetAware();
+ assertEquals("Interface mismatch", mWifiNanIfaceMock, mDut.getWifiNanIface());
+
+ // 6. release (nop - reference counting requests)
+ mDut.releaseAware();
+ assertEquals("Interface mismatch", mWifiNanIfaceMock, mDut.getWifiNanIface());
+
+ // 7. release (interface released)
+ mDut.releaseAware();
+ mInOrder.verify(mHalDeviceManager).removeIface(mWifiNanIfaceMock);
+ assertNull("Interface non-null!", mDut.getWifiNanIface());
+
+ mDestroyedListenerCaptor.getValue().onDestroyed("nan0");
+
+ mInOrder.verify(mHalDeviceManager, never()).createNanIface(any(), any());
+ mInOrder.verify(mHalDeviceManager, never()).removeIface(any());
+ verifyNoMoreInteractions(mWifiAwareStateManagerMock);
+ }
+
+ /**
+ * Test the control flow when the interface gets deleted due to external
+ */
+ @Test
+ public void testRequestFlowWithAsyncDeletes() {
+ // configure HalDeviceManager as ready/wifi started (and to return an interface if
+ // requested)
+ when(mHalDeviceManager.isReady()).thenReturn(true);
+ when(mHalDeviceManager.isStarted()).thenReturn(true);
+ when(mHalDeviceManager.createNanIface(any(), any())).thenReturn(mWifiNanIfaceMock);
+
+ // 1. onStatusChange (ready/started)
+ mManagerStatusListenerCaptor.getValue().onStatusChanged();
+ mInOrder.verify(mHalDeviceManager).registerInterfaceAvailableForRequestListener(
+ eq(IfaceType.NAN), mAvailListenerCaptor.capture(), any(Handler.class));
+ assertNull("Interface non-null!", mDut.getWifiNanIface());
+
+ mAvailListenerCaptor.getValue().onAvailabilityChanged(true);
+ mInOrder.verify(mWifiAwareStateManagerMock).enableUsage();
+
+ // 2. request (interface obtained)
+ mDut.tryToGetAware();
+ mInOrder.verify(mHalDeviceManager).createNanIface(mDestroyedListenerCaptor.capture(),
+ any());
+ assertEquals("Interface mismatch", mWifiNanIfaceMock, mDut.getWifiNanIface());
+
+ // 3. interface gets destroyed
+ mDestroyedListenerCaptor.getValue().onDestroyed("nan0");
+
+ mInOrder.verify(mWifiAwareStateManagerMock).disableUsage();
+ assertNull("Interface non-null!", mDut.getWifiNanIface());
+
+ // 4. a release doesn't do much
+ mDut.releaseAware();
+
+ mInOrder.verify(mHalDeviceManager, never()).createNanIface(any(), any());
+ mInOrder.verify(mHalDeviceManager, never()).removeIface(any());
verifyNoMoreInteractions(mWifiAwareStateManagerMock);
}
}
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..a12e41f 100644
--- a/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareServiceImplTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareServiceImplTest.java
@@ -16,32 +16,40 @@
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.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doNothing;
+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.os.test.TestLooper;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.SparseArray;
import android.util.SparseIntArray;
+import com.android.server.wifi.FrameworkFacade;
+import com.android.server.wifi.util.WifiPermissionsUtil;
import com.android.server.wifi.util.WifiPermissionsWrapper;
import org.junit.Before;
@@ -52,6 +60,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.
@@ -62,6 +73,8 @@
private WifiAwareServiceImplSpy mDut;
private int mDefaultUid = 1500;
+ private String mPackageName = "some.package";
+ private TestLooper mMockLooper;
@Mock
private Context mContextMock;
@@ -80,9 +93,10 @@
@Mock
private IWifiAwareDiscoverySessionCallback mSessionCallbackMock;
@Mock private WifiAwareMetrics mAwareMetricsMock;
+ @Mock private WifiPermissionsUtil mWifiPermissionsUtil;
@Mock private WifiPermissionsWrapper mPermissionsWrapperMock;
-
- private HandlerThread mHandlerThread;
+ @Mock
+ FrameworkFacade mFrameworkFacade;
/**
* Using instead of spy to avoid native crash failures - possibly due to
@@ -111,17 +125,26 @@
@Before
public void setup() throws Exception {
MockitoAnnotations.initMocks(this);
+ mMockLooper = new TestLooper();
+
+ when(mHandlerThreadMock.getLooper()).thenReturn(mMockLooper.getLooper());
+ doNothing().when(mFrameworkFacade).registerContentObserver(eq(mContextMock), any(),
+ anyBoolean(), any());
when(mContextMock.getApplicationContext()).thenReturn(mContextMock);
when(mContextMock.getPackageManager()).thenReturn(mPackageManagerMock);
when(mPackageManagerMock.hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE))
.thenReturn(true);
+ when(mPackageManagerMock.hasSystemFeature(PackageManager.FEATURE_WIFI_RTT))
+ .thenReturn(true);
when(mAwareStateManagerMock.getCharacteristics()).thenReturn(getCharacteristics());
mDut = new WifiAwareServiceImplSpy(mContextMock);
mDut.fakeUid = mDefaultUid;
mDut.start(mHandlerThreadMock, mAwareStateManagerMock, mWifiAwareShellCommandMock,
- mAwareMetricsMock, mPermissionsWrapperMock);
+ mAwareMetricsMock, mWifiPermissionsUtil, mPermissionsWrapperMock, mFrameworkFacade,
+ mock(WifiAwareNativeManager.class), mock(WifiAwareNativeApi.class),
+ mock(WifiAwareNativeCallback.class));
verify(mAwareStateManagerMock).start(eq(mContextMock), any(), eq(mAwareMetricsMock),
eq(mPermissionsWrapperMock));
}
@@ -227,13 +250,48 @@
PublishConfig publishConfig = new PublishConfig.Builder().setServiceName("valid.value")
.build();
- mDut.publish(clientId, publishConfig, mSessionCallbackMock);
+ mDut.publish(mPackageName, clientId, publishConfig, mSessionCallbackMock);
verify(mAwareStateManagerMock).publish(clientId, publishConfig, mSessionCallbackMock);
assertTrue("SecurityException for invalid access from wrong UID thrown", failsAsExpected);
}
/**
+ * Validate that the RTT feature support is checked when attempting a Publish with ranging.
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testFailOnPublishRangingWithoutRttFeature() throws Exception {
+ when(mPackageManagerMock.hasSystemFeature(PackageManager.FEATURE_WIFI_RTT)).thenReturn(
+ false);
+
+ PublishConfig publishConfig = new PublishConfig.Builder().setServiceName("something.valid")
+ .setRangingEnabled(true).build();
+ int clientId = doConnect();
+ IWifiAwareDiscoverySessionCallback mockCallback = mock(
+ IWifiAwareDiscoverySessionCallback.class);
+
+ mDut.publish(mPackageName, clientId, publishConfig, mockCallback);
+ }
+
+ /**
+ * Validate that the RTT feature support is checked when attempting a Subscribe with ranging.
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testFailOnSubscribeRangingWithoutRttFeature() throws Exception {
+ when(mPackageManagerMock.hasSystemFeature(PackageManager.FEATURE_WIFI_RTT)).thenReturn(
+ false);
+
+ SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().setServiceName(
+ "something.valid").setMaxDistanceMm(100).build();
+ int clientId = doConnect();
+ IWifiAwareDiscoverySessionCallback mockCallback = mock(
+ IWifiAwareDiscoverySessionCallback.class);
+
+ mDut.subscribe(mPackageName, clientId, subscribeConfig, mockCallback);
+ }
+
+
+ /**
* Validates that on binder death we get a disconnect().
*/
@Test
@@ -291,12 +349,12 @@
@Test
public void testPublish() {
PublishConfig publishConfig = new PublishConfig.Builder().setServiceName("something.valid")
- .build();
+ .setRangingEnabled(true).build();
int clientId = doConnect();
IWifiAwareDiscoverySessionCallback mockCallback = mock(
IWifiAwareDiscoverySessionCallback.class);
- mDut.publish(clientId, publishConfig, mockCallback);
+ mDut.publish(mPackageName, clientId, publishConfig, mockCallback);
verify(mAwareStateManagerMock).publish(clientId, publishConfig, mockCallback);
}
@@ -386,12 +444,12 @@
@Test
public void testSubscribe() {
SubscribeConfig subscribeConfig = new SubscribeConfig.Builder()
- .setServiceName("something.valid").build();
+ .setServiceName("something.valid").setMaxDistanceMm(100).build();
int clientId = doConnect();
IWifiAwareDiscoverySessionCallback mockCallback = mock(
IWifiAwareDiscoverySessionCallback.class);
- mDut.subscribe(clientId, subscribeConfig, mockCallback);
+ mDut.subscribe(mPackageName, clientId, subscribeConfig, mockCallback);
verify(mAwareStateManagerMock).subscribe(clientId, subscribeConfig, mockCallback);
}
@@ -510,63 +568,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 +616,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,22 +624,18 @@
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);
- mDut.publish(clientId, publishConfig, mockCallback);
+ mDut.publish(mPackageName, clientId, publishConfig, mockCallback);
verify(mAwareStateManagerMock).publish(clientId, publishConfig, mockCallback);
}
@@ -609,12 +646,12 @@
// 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);
- mDut.subscribe(clientId, subscribeConfig, mockCallback);
+ mDut.subscribe(mPackageName, clientId, subscribeConfig, mockCallback);
verify(mAwareStateManagerMock).subscribe(clientId, subscribeConfig, mockCallback);
}
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..765d868 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,17 +3065,20 @@
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();
+ inOrder.verify(mMockNativeManager).tryToGetAware();
inOrder.verify(mMockNative).getCapabilities(transactionId.capture());
mDut.onCapabilitiesUpdateResponse(transactionId.getValue(), getCapabilities());
mMockLooper.dispatchAll();
+ inOrder.verify(mMockNativeManager).releaseAware();
// (1) connect
mDut.connect(clientId, uid, pid, callingPackage, mockCallback, configRequest, false);
mMockLooper.dispatchAll();
+ inOrder.verify(mMockNativeManager).tryToGetAware();
inOrder.verify(mMockNative).enableAndConfigure(transactionId.capture(),
eq(configRequest), eq(false), eq(true), eq(true), eq(false));
mDut.onConfigSuccessResponse(transactionId.getValue());
@@ -3150,13 +3198,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 +3300,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..99add0f
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/hotspot2/OsuNetworkConnectionTest.java
@@ -0,0 +1,263 @@
+/*
+ * 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.anyInt;
+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.ConnectivityManager;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkRequest;
+import android.net.NetworkUtils;
+import android.net.RouteInfo;
+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;
+
+import java.net.InetAddress;
+
+/**
+ * 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 OsuNetworkConnection mNetworkConnection;
+ private TestLooper mLooper;
+ private Handler mHandler;
+
+ @Mock Context mContext;
+ @Mock WifiManager mWifiManager;
+ @Mock ConnectivityManager mConnectivityManager;
+ @Mock OsuNetworkConnection.Callbacks mNetworkCallbacks;
+ @Mock WifiInfo mWifiInfo;
+ @Mock Network mCurrentNetwork;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ doReturn(mWifiManager).when(mContext)
+ .getSystemService(eq(Context.WIFI_SERVICE));
+ doReturn(mConnectivityManager).when(mContext)
+ .getSystemService(eq(Context.CONNECTIVITY_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(mWifiInfo.getNetworkId()).thenReturn(TEST_NETWORK_ID);
+ mLooper = new TestLooper();
+ mHandler = new Handler(mLooper.getLooper());
+ mNetworkConnection = new OsuNetworkConnection(mContext);
+ mNetworkConnection.enableVerboseLogging(ENABLE_LOGGING);
+ }
+
+ private LinkProperties createProvisionedLinkProperties() {
+ InetAddress addrV4 = NetworkUtils.numericToInetAddress("75.208.6.1");
+ InetAddress dns1 = NetworkUtils.numericToInetAddress("75.208.7.1");
+ LinkAddress linkAddrV4 = new LinkAddress(addrV4, 32);
+ InetAddress gateway1 = NetworkUtils.numericToInetAddress("75.208.8.1");
+ LinkProperties lp4 = new LinkProperties();
+ lp4.addLinkAddress(linkAddrV4);
+ lp4.addDnsServer(dns1);
+ lp4.addRoute(new RouteInfo(gateway1));
+ return lp4;
+ }
+
+ /**
+ * 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);
+
+ ArgumentCaptor<IntentFilter> intentFilterCaptor =
+ ArgumentCaptor.forClass(IntentFilter.class);
+ verify(mContext).registerReceiver(any(BroadcastReceiver.class),
+ intentFilterCaptor.capture(), any(), eq(mHandler));
+ verify(mWifiManager).isWifiEnabled();
+ IntentFilter intentFilter = intentFilterCaptor.getValue();
+ assertEquals(intentFilter.countActions(), 1);
+ }
+
+ /**
+ * 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);
+ ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
+ ArgumentCaptor.forClass(BroadcastReceiver.class);
+ verify(mContext).registerReceiver(broadcastReceiverCaptor.capture(),
+ any(IntentFilter.class), any(), eq(mHandler));
+ BroadcastReceiver broadcastReceiver = broadcastReceiverCaptor.getValue();
+ mLooper.dispatchAll();
+ mNetworkConnection.setEventCallback(mNetworkCallbacks);
+ TestUtil.sendWifiStateChanged(broadcastReceiver, mContext,
+ WifiManager.WIFI_STATE_ENABLED);
+ TestUtil.sendWifiStateChanged(broadcastReceiver, mContext,
+ WifiManager.WIFI_STATE_DISABLED);
+ mNetworkConnection.setEventCallback(null);
+ TestUtil.sendWifiStateChanged(broadcastReceiver, mContext,
+ WifiManager.WIFI_STATE_ENABLED);
+ TestUtil.sendWifiStateChanged(broadcastReceiver, 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));
+ verify(mWifiManager, never()).removeNetwork(TEST_NETWORK_ID);
+ }
+
+ /**
+ * 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 network callbacks
+ * are received and when WifiManager has successfully requested connection to the OSU AP.
+ * Ensure IP connectivity is available before invoking onConnected callback.
+ */
+ @Test
+ public void verifyNetworkCallbackInvokedWhenConnected() {
+ mNetworkConnection.init(mHandler);
+
+ mNetworkConnection.setEventCallback(mNetworkCallbacks);
+ assertEquals(true, mNetworkConnection.connect(TEST_SSID, TEST_NAI));
+
+ ArgumentCaptor<ConnectivityManager.NetworkCallback> networkCallbackCaptor =
+ ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class);
+ verify(mConnectivityManager).requestNetwork(any(NetworkRequest.class),
+ networkCallbackCaptor.capture(), any(Handler.class), anyInt());
+ ConnectivityManager.NetworkCallback callback = networkCallbackCaptor.getValue();
+ callback.onLinkPropertiesChanged(mCurrentNetwork, createProvisionedLinkProperties());
+ verify(mNetworkCallbacks).onConnected(mCurrentNetwork);
+
+ callback.onLost(mCurrentNetwork);
+ verify(mNetworkCallbacks).onDisconnected();
+ mNetworkConnection.disconnectIfNeeded();
+ verify(mWifiManager).removeNetwork(TEST_NETWORK_ID);
+ }
+
+ /**
+ * Verifies that network state callbacks are invoked when the network callbacks
+ * are received and when WifiManager has successfully requested connection to the OSU AP.
+ * If IP connectivity is not provisioned, do not invoke onConnected callback.
+ */
+ @Test
+ public void verifyNetworkConnectionTimeout() {
+ mNetworkConnection.init(mHandler);
+
+ mNetworkConnection.setEventCallback(mNetworkCallbacks);
+ assertEquals(true, mNetworkConnection.connect(TEST_SSID, TEST_NAI));
+
+ ArgumentCaptor<ConnectivityManager.NetworkCallback> networkCallbackCaptor =
+ ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class);
+ verify(mConnectivityManager).requestNetwork(any(NetworkRequest.class),
+ networkCallbackCaptor.capture(), any(Handler.class), anyInt());
+ ConnectivityManager.NetworkCallback callback = networkCallbackCaptor.getValue();
+ callback.onLinkPropertiesChanged(mCurrentNetwork, new LinkProperties());
+ verify(mNetworkCallbacks, never()).onConnected(mCurrentNetwork);
+
+ callback.onUnavailable();
+ verify(mNetworkCallbacks).onTimeOut();
+ mNetworkConnection.disconnectIfNeeded();
+ 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 verifyNetworkDisconnect() {
+ 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/OsuServerConnectionTest.java b/tests/wifitests/src/com/android/server/wifi/hotspot2/OsuServerConnectionTest.java
new file mode 100644
index 0000000..60a8b08
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/hotspot2/OsuServerConnectionTest.java
@@ -0,0 +1,113 @@
+/*
+ * 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.doThrow;
+import static org.mockito.Mockito.when;
+
+import android.net.Network;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import javax.net.ssl.HttpsURLConnection;
+
+/**
+ * Unit tests for {@link com.android.server.wifi.hotspot2.OsuServerConnection}.
+ */
+@SmallTest
+public class OsuServerConnectionTest {
+ private static final String TAG = "OsuServerConnectionTest";
+
+ private static final String TEST_URL = "http://www.example.com/";
+ private static final String TLS_VERSION = "TLSv1";
+ private static final String TLS_VERSION_INVALID = "xx";
+ private static final int ENABLE_VERBOSE_LOGGING = 1;
+ private static final int TEST_SESSION_ID = 1;
+
+ private OsuServerConnection mOsuServerConnection;
+ private URL mServerUrl;
+
+ @Mock PasspointProvisioner.OsuServerCallbacks mOsuServerCallbacks;
+ @Mock Network mNetwork;
+ @Mock HttpsURLConnection mUrlConnection;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mOsuServerConnection = new OsuServerConnection();
+ mOsuServerConnection.enableVerboseLogging(ENABLE_VERBOSE_LOGGING);
+ when(mOsuServerCallbacks.getSessionId()).thenReturn(TEST_SESSION_ID);
+ when(mNetwork.openConnection(any(URL.class))).thenReturn(mUrlConnection);
+ try {
+ mServerUrl = new URL(TEST_URL);
+ } catch (MalformedURLException e) {
+ // Test code, will not happen
+ }
+ }
+
+ /**
+ * Verifies initialization and connecting to the OSU server
+ */
+ @Test
+ public void verifyInitAndConnect() {
+ mOsuServerConnection.init(TLS_VERSION);
+ mOsuServerConnection.setEventCallback(mOsuServerCallbacks);
+ assertTrue(mOsuServerConnection.connect(mServerUrl, mNetwork));
+ }
+
+ /**
+ * Verifies initialization of the HTTPS connection with invalid TLS algorithm
+ */
+ @Test
+ public void verifyInitFailure() {
+ mOsuServerConnection.init(TLS_VERSION_INVALID);
+ mOsuServerConnection.setEventCallback(mOsuServerCallbacks);
+ assertFalse(mOsuServerConnection.canValidateServer());
+ }
+
+ /**
+ * Verifies initialization and opening URL connection failed on the network
+ */
+ @Test
+ public void verifyInitAndNetworkOpenURLConnectionFailed() throws IOException {
+ mOsuServerConnection.init(TLS_VERSION);
+ mOsuServerConnection.setEventCallback(mOsuServerCallbacks);
+ doThrow(new IOException()).when(mNetwork).openConnection(any(URL.class));
+ assertFalse(mOsuServerConnection.connect(mServerUrl, mNetwork));
+ }
+
+ /**
+ * Verifies initialization and connection failure to OSU server
+ */
+ @Test
+ public void verifyInitAndServerConnectFailure() throws IOException {
+ mOsuServerConnection.init(TLS_VERSION);
+ mOsuServerConnection.setEventCallback(mOsuServerCallbacks);
+ doThrow(new IOException()).when(mUrlConnection).connect();
+ assertFalse(mOsuServerConnection.connect(mServerUrl, mNetwork));
+ }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointConfigStoreDataTest.java b/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointConfigStoreDataTest.java
index 7e05c3d..8441eb0 100644
--- a/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointConfigStoreDataTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointConfigStoreDataTest.java
@@ -61,6 +61,7 @@
private static final long TEST_PROVIDER_ID = 1;
private static final int TEST_CREATOR_UID = 1234;
private static final boolean TEST_HAS_EVER_CONNECTED = true;
+ private static final boolean TEST_SHARED = false;
@Mock WifiKeyStore mKeyStore;
@Mock SIMAccessor mSimAccessor;
@@ -239,7 +240,7 @@
providerList.add(new PasspointProvider(createFullPasspointConfiguration(),
mKeyStore, mSimAccessor, TEST_PROVIDER_ID, TEST_CREATOR_UID,
TEST_CA_CERTIFICATE_ALIAS, TEST_CLIENT_CERTIFICATE_ALIAS,
- TEST_CLIENT_PRIVATE_KEY_ALIAS, TEST_HAS_EVER_CONNECTED));
+ TEST_CLIENT_PRIVATE_KEY_ALIAS, TEST_HAS_EVER_CONNECTED, TEST_SHARED));
// Serialize data for user store.
when(mDataSource.getProviders()).thenReturn(providerList);
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..f14e607 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,12 @@
@Mock WifiConfigStore mWifiConfigStore;
@Mock PasspointConfigStoreData.DataSource mDataSource;
@Mock WifiMetrics mWifiMetrics;
+ @Mock OsuNetworkConnection mOsuNetworkConnection;
+ @Mock OsuServerConnection mOsuServerConnection;
+ @Mock PasspointProvisioner mPasspointProvisioner;
+ @Mock IProvisioningCallback mCallback;
+
+ TestLooper mLooper;
PasspointManager mManager;
/** Sets up test. */
@@ -140,6 +152,13 @@
when(mObjectFactory.makeANQPRequestManager(any(), eq(mClock)))
.thenReturn(mAnqpRequestManager);
when(mObjectFactory.makeCertificateVerifier()).thenReturn(mCertVerifier);
+ when(mObjectFactory.makeOsuNetworkConnection(any(Context.class)))
+ .thenReturn(mOsuNetworkConnection);
+ when(mObjectFactory.makeOsuServerConnection())
+ .thenReturn(mOsuServerConnection);
+ when(mObjectFactory.makePasspointProvisioner(any(Context.class),
+ any(OsuNetworkConnection.class), any(OsuServerConnection.class)))
+ .thenReturn(mPasspointProvisioner);
mManager = new PasspointManager(mContext, mWifiNative, mWifiKeyStore, mClock,
mSimAccessor, mObjectFactory, mWifiConfigManager, mWifiConfigStore, mWifiMetrics);
ArgumentCaptor<PasspointEventHandler.Callbacks> callbacks =
@@ -152,6 +171,7 @@
any(WifiKeyStore.class), any(SIMAccessor.class), dataSource.capture());
mCallbacks = callbacks.getValue();
mDataSource = dataSource.getValue();
+ mLooper = new TestLooper();
}
/**
@@ -208,10 +228,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 +274,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 +457,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 +472,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 +575,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 +600,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 +617,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 +633,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 +674,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 +690,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 +708,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 +726,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 +781,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 +800,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 +819,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 +879,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 +1065,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 +1089,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 +1336,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 +1351,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 +1365,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 +1384,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/PasspointProviderTest.java b/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointProviderTest.java
index 9ee9fc6..355c252 100644
--- a/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointProviderTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointProviderTest.java
@@ -650,6 +650,7 @@
assertTrue(Arrays.equals(rcOIs, wifiConfig.roamingConsortiumIds));
assertTrue(wifiConfig.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_EAP));
assertTrue(wifiConfig.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.IEEE8021X));
+ assertFalse(wifiConfig.shared);
assertEquals(realm, wifiEnterpriseConfig.getRealm());
assertEquals(fqdn, wifiEnterpriseConfig.getDomainSuffixMatch());
assertEquals("anonymous@" + realm, wifiEnterpriseConfig.getAnonymousIdentity());
@@ -712,6 +713,7 @@
assertTrue(Arrays.equals(rcOIs, wifiConfig.roamingConsortiumIds));
assertTrue(wifiConfig.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_EAP));
assertTrue(wifiConfig.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.IEEE8021X));
+ assertFalse(wifiConfig.shared);
assertEquals(realm, wifiEnterpriseConfig.getRealm());
assertEquals(fqdn, wifiEnterpriseConfig.getDomainSuffixMatch());
assertEquals("anonymous@" + realm, wifiEnterpriseConfig.getAnonymousIdentity());
@@ -761,6 +763,7 @@
assertTrue(Arrays.equals(rcOIs, wifiConfig.roamingConsortiumIds));
assertTrue(wifiConfig.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_EAP));
assertTrue(wifiConfig.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.IEEE8021X));
+ assertFalse(wifiConfig.shared);
assertEquals(realm, wifiEnterpriseConfig.getRealm());
assertEquals(fqdn, wifiEnterpriseConfig.getDomainSuffixMatch());
assertEquals(WifiEnterpriseConfig.Eap.SIM, wifiEnterpriseConfig.getEapMethod());
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..13761cc
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointProvisionerTest.java
@@ -0,0 +1,404 @@
+/*
+ * 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.atLeastOnce;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.net.Network;
+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.ProvisioningCallback;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.test.TestLooper;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.net.URL;
+
+/**
+ * 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();
+ private Handler mHandler;
+ private OsuNetworkConnection.Callbacks mOsuNetworkCallbacks;
+ private PasspointProvisioner.OsuServerCallbacks mOsuServerCallbacks;
+ private ArgumentCaptor<OsuNetworkConnection.Callbacks> mOsuNetworkCallbacksCaptor =
+ ArgumentCaptor.forClass(OsuNetworkConnection.Callbacks.class);
+ private ArgumentCaptor<PasspointProvisioner.OsuServerCallbacks> mOsuServerCallbacksCaptor =
+ ArgumentCaptor.forClass(PasspointProvisioner.OsuServerCallbacks.class);
+ private ArgumentCaptor<Handler> mHandlerCaptor = ArgumentCaptor.forClass(Handler.class);
+ private OsuProvider mOsuProvider;
+
+ @Mock Context mContext;
+ @Mock WifiManager mWifiManager;
+ @Mock IProvisioningCallback mCallback;
+ @Mock OsuNetworkConnection mOsuNetworkConnection;
+ @Mock OsuServerConnection mOsuServerConnection;
+ @Mock Network mNetwork;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ when(mWifiManager.isWifiEnabled()).thenReturn(true);
+ doReturn(mWifiManager).when(mContext)
+ .getSystemService(eq(Context.WIFI_SERVICE));
+ mPasspointProvisioner = new PasspointProvisioner(mContext, mOsuNetworkConnection,
+ mOsuServerConnection);
+ when(mOsuNetworkConnection.connect(any(WifiSsid.class), any())).thenReturn(true);
+ when(mOsuServerConnection.connect(any(URL.class), any(Network.class))).thenReturn(true);
+ when(mOsuServerConnection.validateProvider(any(String.class))).thenReturn(true);
+ when(mOsuServerConnection.canValidateServer()).thenReturn(true);
+ mPasspointProvisioner.enableVerboseLogging(1);
+ mOsuProvider = PasspointProvisioningTestUtil.generateOsuProvider(true);
+ }
+
+ private void initAndStartProvisioning() {
+ mPasspointProvisioner.init(mLooper.getLooper());
+ verify(mOsuNetworkConnection).init(mHandlerCaptor.capture());
+ verify(mOsuServerConnection).init(any(String.class));
+
+ mHandler = mHandlerCaptor.getValue();
+ assertEquals(mHandler.getLooper(), mLooper.getLooper());
+
+ assertTrue(mPasspointProvisioner.startSubscriptionProvisioning(
+ TEST_UID, mOsuProvider, mCallback));
+ // Runnable posted by the provisioning start request
+ assertEquals(mHandler.hasMessagesOrCallbacks(), true);
+ mLooper.dispatchAll();
+ assertEquals(mHandler.hasMessagesOrCallbacks(), false);
+
+ verify(mOsuNetworkConnection, atLeastOnce())
+ .setEventCallback(mOsuNetworkCallbacksCaptor.capture());
+ mOsuNetworkCallbacks = mOsuNetworkCallbacksCaptor.getAllValues().get(0);
+ verify(mOsuServerConnection, atLeastOnce())
+ .setEventCallback(mOsuServerCallbacksCaptor.capture());
+ mOsuServerCallbacks = mOsuServerCallbacksCaptor.getAllValues().get(0);
+ }
+
+ /**
+ * Verifies initialization and starting subscription provisioning flow
+ */
+ @Test
+ public void verifyInitAndStartProvisioning() throws RemoteException {
+ initAndStartProvisioning();
+ }
+
+ /**
+ * Verifies initialization and starting subscription provisioning flow
+ */
+ @Test
+ public void verifyProvisioningUnavailable() throws RemoteException {
+ when(mOsuServerConnection.canValidateServer()).thenReturn(false);
+ initAndStartProvisioning();
+ verify(mCallback).onProvisioningFailure(
+ ProvisioningCallback.OSU_FAILURE_PROVISIONING_NOT_AVAILABLE);
+ }
+
+ /**
+ * Verifies existing provisioning flow is aborted before starting another one.
+ */
+ @Test
+ public void verifyProvisioningAbort() throws RemoteException {
+ initAndStartProvisioning();
+ verify(mCallback).onProvisioningStatus(
+ ProvisioningCallback.OSU_STATUS_AP_CONNECTING);
+ IProvisioningCallback mCallback2 = mock(IProvisioningCallback.class);
+ assertTrue(mPasspointProvisioner.startSubscriptionProvisioning(
+ TEST_UID, mOsuProvider, mCallback2));
+ // Runnable posted by the provisioning start request
+ assertEquals(mHandler.hasMessagesOrCallbacks(), true);
+ mLooper.dispatchAll();
+ assertEquals(mHandler.hasMessagesOrCallbacks(), false);
+ verify(mCallback).onProvisioningFailure(
+ ProvisioningCallback.OSU_FAILURE_PROVISIONING_ABORTED);
+ }
+
+ /**
+ * Verifies that the right provisioning callbacks are invoked as the provisioner progresses
+ * to associating with the OSU AP, connecting to the OSU Server, validating its certificates
+ * and verifying the OSU provider.
+ */
+ @Test
+ public void verifyProvisioningFlow() throws RemoteException {
+ initAndStartProvisioning();
+ // state exptected is WAITING_TO_CONNECT
+ verify(mCallback).onProvisioningStatus(ProvisioningCallback.OSU_STATUS_AP_CONNECTING);
+ // Connection to OSU AP successful
+ mOsuNetworkCallbacks.onConnected(mNetwork);
+ // state expected is OSU_AP_CONNECTED
+ verify(mCallback).onProvisioningStatus(ProvisioningCallback.OSU_STATUS_AP_CONNECTED);
+ // state expected is OSU_SERVER_CONNECTED
+ verify(mCallback).onProvisioningStatus(ProvisioningCallback.OSU_STATUS_SERVER_CONNECTED);
+ // Wait for server validation status
+ assertFalse(mHandler.hasMessagesOrCallbacks());
+ // Server validation passed
+ mOsuServerCallbacks.onServerValidationStatus(mOsuServerCallbacks.getSessionId(), true);
+ assertTrue(mHandler.hasMessagesOrCallbacks());
+ mLooper.dispatchAll();
+ // state expected is OSU_SERVER_VALIDATED
+ verify(mCallback).onProvisioningStatus(ProvisioningCallback.OSU_STATUS_SERVER_VALIDATED);
+ // state expected is OSU_PROVIDER_VALIDATED
+ verify(mCallback).onProvisioningStatus(ProvisioningCallback.OSU_STATUS_PROVIDER_VERIFIED);
+ // Osu provider verification is the last current step in the flow, no more runnables posted.
+ assertFalse(mHandler.hasMessagesOrCallbacks());
+ }
+
+ /**
+ * Verifies that if connection attempt to OSU AP fails, corresponding error callback is invoked.
+ */
+ @Test
+ public void verifyConnectAttemptFailure() throws RemoteException {
+ when(mOsuNetworkConnection.connect(any(WifiSsid.class), any())).thenReturn(false);
+ initAndStartProvisioning();
+
+ // Since connection attempt fails, directly move to FAILED_STATE
+ verify(mCallback).onProvisioningFailure(ProvisioningCallback.OSU_FAILURE_AP_CONNECTION);
+ // Failure case, no more runnables posted
+ assertFalse(mHandler.hasMessagesOrCallbacks());
+ }
+
+ /**
+ * Verifies that after connection attemp succeeds and a network disconnection occurs, the
+ * corresponding failure callback is invoked.
+ */
+ @Test
+ public void verifyConnectAttemptedAndConnectionFailed() throws RemoteException {
+ initAndStartProvisioning();
+
+ // state expected is WAITING_TO_CONNECT
+ verify(mCallback).onProvisioningStatus(ProvisioningCallback.OSU_STATUS_AP_CONNECTING);
+ // Connection to OSU AP fails
+ mOsuNetworkCallbacks.onDisconnected();
+ // Move to failed state
+ verify(mCallback).onProvisioningFailure(ProvisioningCallback.OSU_FAILURE_AP_CONNECTION);
+ // Failure case, no more runnables posted
+ assertEquals(mHandler.hasMessagesOrCallbacks(), false);
+ }
+
+ /**
+ * Verifies that a connection drop is reported via callback.
+ */
+ @Test
+ public void verifyConnectionDrop() throws RemoteException {
+ initAndStartProvisioning();
+ // state expected WAITING_TO_CONNECT
+ verify(mCallback).onProvisioningStatus(ProvisioningCallback.OSU_STATUS_AP_CONNECTING);
+ // Connection to OSU AP successful
+ mOsuNetworkCallbacks.onConnected(mNetwork);
+ // state expected OSU_AP_CONNECTED
+ verify(mCallback).onProvisioningStatus(ProvisioningCallback.OSU_STATUS_AP_CONNECTED);
+ // state expected OSU_SERVER_CONNECTED
+ verify(mCallback).onProvisioningStatus(ProvisioningCallback.OSU_STATUS_SERVER_CONNECTED);
+ // Disconnect received
+ mOsuNetworkCallbacks.onDisconnected();
+ // Move to failed state
+ verify(mCallback).onProvisioningFailure(ProvisioningCallback.OSU_FAILURE_AP_CONNECTION);
+ // No more callbacks, Osu server validation not initiated
+ assertFalse(mHandler.hasMessagesOrCallbacks());
+ }
+
+ /**
+ * Verifies that Wifi Disable while provisioning is communicated as provisioning failure
+ */
+ @Test
+ public void verifyFailureDueToWifiDisable() throws RemoteException {
+ initAndStartProvisioning();
+ // state expected WAITING_TO_CONNECT
+ verify(mCallback).onProvisioningStatus(ProvisioningCallback.OSU_STATUS_AP_CONNECTING);
+ // Connection to OSU AP successful
+ mOsuNetworkCallbacks.onConnected(mNetwork);
+ // state expected is OSU_AP_CONNECTED
+ verify(mCallback).onProvisioningStatus(ProvisioningCallback.OSU_STATUS_AP_CONNECTED);
+ // state expecte is OSU_SERVER_CONNECTED
+ verify(mCallback).onProvisioningStatus(ProvisioningCallback.OSU_STATUS_SERVER_CONNECTED);
+ // Wifi disabled notification
+ mOsuNetworkCallbacks.onWifiDisabled();
+ // Wifi Disable is processed first and move to failed state
+ verify(mCallback).onProvisioningFailure(ProvisioningCallback.OSU_FAILURE_AP_CONNECTION);
+ // OSU server connection event is not handled
+ assertFalse(mHandler.hasMessagesOrCallbacks());
+ }
+
+ /**
+ * Verifies that the right provisioning callbacks are invoked as the provisioner connects
+ * to OSU AP and OSU server and that invalid server URL generates the right error callback.
+ */
+ @Test
+ public void verifyInvalidOsuServerURL() throws RemoteException {
+ mOsuProvider = PasspointProvisioningTestUtil.generateInvalidServerUrlOsuProvider();
+ initAndStartProvisioning();
+ // Attempting to connect to OSU server fails due to invalid server URL, move to failed state
+ verify(mCallback).onProvisioningFailure(
+ ProvisioningCallback.OSU_FAILURE_SERVER_URL_INVALID);
+ // No further runnables posted
+ assertEquals(mHandler.hasMessagesOrCallbacks(), false);
+ }
+
+ /**
+ * Verifies that the right provisioning callbacks are invoked as the provisioner progresses
+ * to associating with the OSU AP and connection to OSU server fails.
+ */
+ @Test
+ public void verifyServerConnectionFailure() throws RemoteException {
+ initAndStartProvisioning();
+ when(mOsuServerConnection.connect(any(URL.class), any(Network.class))).thenReturn(false);
+ // expected state is WAITING_TO_CONNECT
+ verify(mCallback).onProvisioningStatus(ProvisioningCallback.OSU_STATUS_AP_CONNECTING);
+ // Connection to OSU AP is successful
+ mOsuNetworkCallbacks.onConnected(mNetwork);
+ // state expected is OSU_AP_CONNECTED
+ verify(mCallback).onProvisioningStatus(ProvisioningCallback.OSU_STATUS_AP_CONNECTED);
+ // Connection to OSU Server fails, move to failed state
+ verify(mCallback).onProvisioningFailure(ProvisioningCallback.OSU_FAILURE_SERVER_CONNECTION);
+ // No further runnables posted
+ assertFalse(mHandler.hasMessagesOrCallbacks());
+ }
+
+ /**
+ * Verifies that the right provisioning callbacks are invoked as the provisioner is unable
+ * to validate the OSU Server
+ */
+ @Test
+ public void verifyServerValidationFailure() throws RemoteException {
+ initAndStartProvisioning();
+ // state expected is WAITING_TO_CONNECT
+ verify(mCallback).onProvisioningStatus(ProvisioningCallback.OSU_STATUS_AP_CONNECTING);
+ // Connection to OSU AP is successful
+ mOsuNetworkCallbacks.onConnected(mNetwork);
+ // state expected is OSU_AP_CONNECTED
+ verify(mCallback).onProvisioningStatus(ProvisioningCallback.OSU_STATUS_AP_CONNECTED);
+ // state expected is OSU_SERVER_CONNECTED
+ verify(mCallback).onProvisioningStatus(ProvisioningCallback.OSU_STATUS_SERVER_CONNECTED);
+ // OSU Server validation of certs fails
+ mOsuServerCallbacks.onServerValidationStatus(mOsuServerCallbacks.getSessionId(), false);
+ // Runnable posted by server callback
+ assertTrue(mHandler.hasMessagesOrCallbacks());
+ mLooper.dispatchAll();
+ // Server validation failure, move to failed state
+ verify(mCallback).onProvisioningFailure(ProvisioningCallback.OSU_FAILURE_SERVER_VALIDATION);
+ // No further runnables posted
+ assertFalse(mHandler.hasMessagesOrCallbacks());
+ }
+
+ /**
+ * Verifies that the status for server validation from a previous session is ignored
+ * by the provisioning state machine
+ */
+ @Test
+ public void verifyServerValidationFailurePreviousSession() throws RemoteException {
+ initAndStartProvisioning();
+ // state expected is WAITING_TO_CONNECT
+ verify(mCallback).onProvisioningStatus(ProvisioningCallback.OSU_STATUS_AP_CONNECTING);
+ // Connection to OSU AP is successful
+ mOsuNetworkCallbacks.onConnected(mNetwork);
+ // state expected is OSU_AP_CONNECTED
+ verify(mCallback).onProvisioningStatus(ProvisioningCallback.OSU_STATUS_AP_CONNECTED);
+ // state expected is OSU_SERVER_CONNECTED
+ verify(mCallback).onProvisioningStatus(ProvisioningCallback.OSU_STATUS_SERVER_CONNECTED);
+ // OSU Server validation of certs failure but from a previous session
+ mOsuServerCallbacks.onServerValidationStatus(mOsuServerCallbacks.getSessionId() - 1, false);
+ // Runnable posted by server callback
+ assertTrue(mHandler.hasMessagesOrCallbacks());
+ mLooper.dispatchAll();
+ // Server validation failure, move to failed state
+ verify(mCallback, never()).onProvisioningFailure(
+ ProvisioningCallback.OSU_FAILURE_SERVER_VALIDATION);
+ // No further runnables posted
+ assertFalse(mHandler.hasMessagesOrCallbacks());
+ }
+
+ /**
+ * Verifies that the status for server validation from a previous session is ignored
+ * by the provisioning state machine
+ */
+ @Test
+ public void verifyServerValidationSuccessPreviousSession() throws RemoteException {
+ initAndStartProvisioning();
+ // state expected is WAITING_TO_CONNECT
+ verify(mCallback).onProvisioningStatus(ProvisioningCallback.OSU_STATUS_AP_CONNECTING);
+ // Connection to OSU AP is successful
+ mOsuNetworkCallbacks.onConnected(mNetwork);
+ // state expected is OSU_AP_CONNECTED
+ verify(mCallback).onProvisioningStatus(ProvisioningCallback.OSU_STATUS_AP_CONNECTED);
+ // state expected is OSU_SERVER_CONNECTED
+ verify(mCallback).onProvisioningStatus(ProvisioningCallback.OSU_STATUS_SERVER_CONNECTED);
+ // OSU Server validation success but from a previous session
+ mOsuServerCallbacks.onServerValidationStatus(mOsuServerCallbacks.getSessionId() - 1, true);
+ // Runnable posted by server callback
+ assertTrue(mHandler.hasMessagesOrCallbacks());
+ mLooper.dispatchAll();
+ // Server validation failure, move to failed state
+ verify(mCallback, never()).onProvisioningStatus(
+ ProvisioningCallback.OSU_STATUS_SERVER_VALIDATED);
+ // No further runnables posted
+ assertFalse(mHandler.hasMessagesOrCallbacks());
+ }
+
+ /**
+ * Verifies that the right provisioning callbacks are invoked when provisioner is unable
+ * to validate the OSU provider
+ */
+ @Test
+ public void verifyProviderVerificationFailure() throws RemoteException {
+ initAndStartProvisioning();
+ when(mOsuServerConnection.validateProvider(any(String.class))).thenReturn(false);
+ // state expected is WAITING_TO_CONNECT
+ verify(mCallback).onProvisioningStatus(ProvisioningCallback.OSU_STATUS_AP_CONNECTING);
+ // Connection to OSU AP successful
+ mOsuNetworkCallbacks.onConnected(mNetwork);
+ // state expected is OSU_AP_CONNECTED
+ verify(mCallback).onProvisioningStatus(ProvisioningCallback.OSU_STATUS_AP_CONNECTED);
+ verify(mCallback).onProvisioningStatus(ProvisioningCallback.OSU_STATUS_SERVER_CONNECTED);
+ // Wait for OSU server validation callback
+ mOsuServerCallbacks.onServerValidationStatus(mOsuServerCallbacks.getSessionId(), true);
+ // Runnable posted by server callback
+ assertTrue(mHandler.hasMessagesOrCallbacks());
+ // OSU server validation success posts another runnable to validate the provider
+ mLooper.dispatchAll();
+ // state expected is OSU_SERVER_VALIDATED
+ verify(mCallback).onProvisioningStatus(ProvisioningCallback.OSU_STATUS_SERVER_VALIDATED);
+ // Provider validation failure is processed next, move to failed state
+ verify(mCallback).onProvisioningFailure(
+ ProvisioningCallback.OSU_FAILURE_PROVIDER_VERIFICATION);
+ // No further runnables posted
+ assertFalse(mHandler.hasMessagesOrCallbacks());
+ }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/p2p/SupplicantP2pIfaceHalTest.java b/tests/wifitests/src/com/android/server/wifi/p2p/SupplicantP2pIfaceHalTest.java
index 24f4854..70b5c77 100644
--- a/tests/wifitests/src/com/android/server/wifi/p2p/SupplicantP2pIfaceHalTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/p2p/SupplicantP2pIfaceHalTest.java
@@ -20,6 +20,7 @@
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.verify;
import static org.mockito.Mockito.when;
@@ -29,6 +30,7 @@
import android.hardware.wifi.supplicant.V1_0.ISupplicantIface;
import android.hardware.wifi.supplicant.V1_0.ISupplicantNetwork;
import android.hardware.wifi.supplicant.V1_0.ISupplicantP2pIface;
+import android.hardware.wifi.supplicant.V1_0.ISupplicantP2pIfaceCallback;
import android.hardware.wifi.supplicant.V1_0.ISupplicantP2pNetwork;
import android.hardware.wifi.supplicant.V1_0.IfaceType;
import android.hardware.wifi.supplicant.V1_0.SupplicantStatus;
@@ -68,11 +70,13 @@
public class SupplicantP2pIfaceHalTest {
private static final String TAG = "SupplicantP2pIfaceHalTest";
private SupplicantP2pIfaceHal mDut;
- @Mock IServiceManager mServiceManagerMock;
- @Mock ISupplicant mISupplicantMock;
- @Mock ISupplicantIface mISupplicantIfaceMock;
- @Mock ISupplicantP2pIface mISupplicantP2pIfaceMock;
- @Mock ISupplicantP2pNetwork mISupplicantP2pNetworkMock;
+ private @Mock IServiceManager mServiceManagerMock;
+ private @Mock ISupplicant mISupplicantMock;
+ private android.hardware.wifi.supplicant.V1_1.ISupplicant mISupplicantMockV1_1;
+ private @Mock ISupplicantIface mISupplicantIfaceMock;
+ private @Mock ISupplicantP2pIface mISupplicantP2pIfaceMock;
+ private @Mock ISupplicantP2pNetwork mISupplicantP2pNetworkMock;
+ private @Mock WifiP2pMonitor mWifiMonitor;
SupplicantStatus mStatusSuccess;
SupplicantStatus mStatusFailure;
@@ -136,7 +140,7 @@
private class SupplicantP2pIfaceHalSpy extends SupplicantP2pIfaceHal {
SupplicantP2pIfaceHalSpy() {
- super(null);
+ super(mWifiMonitor);
}
@Override
@@ -150,6 +154,12 @@
}
@Override
+ protected android.hardware.wifi.supplicant.V1_1.ISupplicant getSupplicantMockableV1_1()
+ throws RemoteException {
+ return mISupplicantMockV1_1;
+ }
+
+ @Override
protected ISupplicantP2pIface getP2pIfaceMockable(ISupplicantIface iface) {
return mISupplicantP2pIfaceMock;
}
@@ -181,6 +191,8 @@
anyLong())).thenReturn(true);
when(mISupplicantP2pIfaceMock.linkToDeath(any(IHwBinder.DeathRecipient.class),
anyLong())).thenReturn(true);
+ when(mISupplicantP2pIfaceMock.registerCallback(any(ISupplicantP2pIfaceCallback.class)))
+ .thenReturn(mStatusSuccess);
mDut = new SupplicantP2pIfaceHalSpy();
}
@@ -221,6 +233,36 @@
}
/**
+ * Sunny day scenario for SupplicantStaIfaceHal initialization
+ * Asserts successful initialization
+ */
+ @Test
+ public void testInitialize_successV1_1() throws Exception {
+ mISupplicantMockV1_1 = mock(android.hardware.wifi.supplicant.V1_1.ISupplicant.class);
+ executeAndValidateInitializationSequenceV1_1(false, false);
+ }
+
+ /**
+ * Tests the initialization flow, with a RemoteException occurring when 'getInterface' is called
+ * Ensures initialization fails.
+ */
+ @Test
+ public void testInitialize_remoteExceptionFailureV1_1() throws Exception {
+ mISupplicantMockV1_1 = mock(android.hardware.wifi.supplicant.V1_1.ISupplicant.class);
+ executeAndValidateInitializationSequenceV1_1(true, false);
+ }
+
+ /**
+ * Tests the initialization flow, with a null interface being returned by getInterface.
+ * Ensures initialization fails.
+ */
+ @Test
+ public void testInitialize_nullInterfaceFailureV1_1() throws Exception {
+ mISupplicantMockV1_1 = mock(android.hardware.wifi.supplicant.V1_1.ISupplicant.class);
+ executeAndValidateInitializationSequenceV1_1(false, true);
+ }
+
+ /**
* Sunny day scenario for getName()
*/
@Test
@@ -2521,28 +2563,89 @@
any(ISupplicant.getInterfaceCallback.class));
}
- mInOrder = inOrder(mServiceManagerMock, mISupplicantMock);
+ mInOrder = inOrder(mServiceManagerMock, mISupplicantMock, mISupplicantP2pIfaceMock);
// Initialize SupplicantP2pIfaceHal, should call serviceManager.registerForNotifications
assertTrue(mDut.initialize());
// verify: service manager initialization sequence
- mInOrder.verify(mServiceManagerMock).linkToDeath(any(IHwBinder.DeathRecipient.class),
- anyLong());
+ mInOrder.verify(mServiceManagerMock).linkToDeath(
+ any(IHwBinder.DeathRecipient.class), anyLong());
mInOrder.verify(mServiceManagerMock).registerForNotifications(
eq(ISupplicant.kInterfaceName), eq(""), mServiceNotificationCaptor.capture());
// act: cause the onRegistration(...) callback to execute
mServiceNotificationCaptor.getValue().onRegistration(ISupplicant.kInterfaceName, "", true);
+ mInOrder.verify(mISupplicantMock).linkToDeath(
+ any(IHwBinder.DeathRecipient.class), anyLong());
assertEquals(shouldSucceed, mDut.isInitializationComplete());
// verify: listInterfaces is called
mInOrder.verify(mISupplicantMock).listInterfaces(
any(ISupplicant.listInterfacesCallback.class));
- if (!getZeroInterfaces) {
+ if (!causeRemoteException && !getNullInterface && !getZeroInterfaces) {
mInOrder.verify(mISupplicantMock)
.getInterface(any(ISupplicant.IfaceInfo.class),
any(ISupplicant.getInterfaceCallback.class));
+ mInOrder.verify(mISupplicantP2pIfaceMock).linkToDeath(
+ any(IHwBinder.DeathRecipient.class), anyLong());
+ mInOrder.verify(mISupplicantP2pIfaceMock).registerCallback(
+ any(ISupplicantP2pIfaceCallback.class));
}
}
+ /**
+ * Calls.initialize(), mocking various call back answers and verifying flow, asserting for the
+ * expected result. Verifies if ISupplicantP2pIface manager is initialized or reset.
+ * Each of the arguments will cause a different failure mode when set true.
+ */
+ private void executeAndValidateInitializationSequenceV1_1(boolean causeRemoteException,
+ boolean getNullInterface)
+ throws Exception {
+ boolean shouldSucceed = !causeRemoteException && !getNullInterface;
+ // Setup callback mock answers
+ if (causeRemoteException) {
+ doThrow(new RemoteException("Some error!!!"))
+ .when(mISupplicantMockV1_1).addInterface(any(ISupplicant.IfaceInfo.class),
+ any(android.hardware.wifi.supplicant.V1_1.ISupplicant
+ .addInterfaceCallback.class));
+ } else {
+ doAnswer(new GetAddInterfaceAnswer(getNullInterface))
+ .when(mISupplicantMockV1_1).addInterface(any(ISupplicant.IfaceInfo.class),
+ any(android.hardware.wifi.supplicant.V1_1.ISupplicant
+ .addInterfaceCallback.class));
+ }
+
+ mInOrder = inOrder(mServiceManagerMock, mISupplicantMock, mISupplicantMockV1_1,
+ mISupplicantP2pIfaceMock);
+ // Initialize SupplicantStaIfaceHal, should call serviceManager.registerForNotifications
+ assertTrue(mDut.initialize());
+ // verify: service manager initialization sequence
+ mInOrder.verify(mServiceManagerMock).linkToDeath(
+ any(IHwBinder.DeathRecipient.class), anyLong());
+ mInOrder.verify(mServiceManagerMock).registerForNotifications(
+ eq(ISupplicant.kInterfaceName), eq(""), mServiceNotificationCaptor.capture());
+ // act: cause the onRegistration(...) callback to execute
+ mServiceNotificationCaptor.getValue().onRegistration(ISupplicant.kInterfaceName, "", true);
+ mInOrder.verify(mISupplicantMock).linkToDeath(
+ any(IHwBinder.DeathRecipient.class), anyLong());
+
+ assertEquals(shouldSucceed, mDut.isInitializationComplete());
+ // verify: addInterface is called
+ mInOrder.verify(mISupplicantMockV1_1)
+ .addInterface(any(ISupplicant.IfaceInfo.class),
+ any(android.hardware.wifi.supplicant.V1_1.ISupplicant
+ .addInterfaceCallback.class));
+ if (!causeRemoteException && !getNullInterface) {
+ mInOrder.verify(mISupplicantP2pIfaceMock).linkToDeath(
+ any(IHwBinder.DeathRecipient.class), anyLong());
+ mInOrder.verify(mISupplicantP2pIfaceMock).registerCallback(
+ any(ISupplicantP2pIfaceCallback.class));
+ }
+
+ // Ensure we don't try to use the listInterfaces method from 1.0 version.
+ verify(mISupplicantMock, never()).listInterfaces(
+ any(ISupplicant.listInterfacesCallback.class));
+ verify(mISupplicantMock, never()).getInterface(any(ISupplicant.IfaceInfo.class),
+ any(ISupplicant.getInterfaceCallback.class));
+ }
private SupplicantStatus createSupplicantStatus(int code) {
SupplicantStatus status = new SupplicantStatus();
@@ -2615,4 +2718,22 @@
}
}
}
+
+ private class GetAddInterfaceAnswer extends AnswerWithArguments {
+ boolean mGetNullInterface;
+
+ GetAddInterfaceAnswer(boolean getNullInterface) {
+ mGetNullInterface = getNullInterface;
+ }
+
+ public void answer(ISupplicant.IfaceInfo iface,
+ android.hardware.wifi.supplicant.V1_1.ISupplicant
+ .addInterfaceCallback cb) {
+ if (mGetNullInterface) {
+ cb.onValues(mStatusSuccess, null);
+ } else {
+ cb.onValues(mStatusSuccess, mISupplicantIfaceMock);
+ }
+ }
+ }
}
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..3f64de9
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/rtt/RttNativeTest.java
@@ -0,0 +1,220 @@
+/*
+ * 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.MacAddress;
+import android.net.wifi.rtt.RangingRequest;
+
+import com.android.server.wifi.HalDeviceManager;
+
+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).enableIfPossible();
+ 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(MacAddress.fromString("00:01:02:03:04:00").toByteArray()));
+ 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(MacAddress.fromString("0A:0B:0C:0D:0E:00").toByteArray()));
+ 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(MacAddress.fromString("08:09:08:07:06:05").toByteArray()));
+ 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(MacAddress.fromString("05:06:07:08:09:0A").toByteArray()));
+ 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..ef15914
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/rtt/RttServiceImplTest.java
@@ -0,0 +1,1204 @@
+/*
+ * 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.anyBoolean;
+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.doNothing;
+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.location.LocationManager;
+import android.net.MacAddress;
+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.provider.Settings;
+import android.util.Pair;
+
+import com.android.server.wifi.Clock;
+import com.android.server.wifi.FrameworkFacade;
+import com.android.server.wifi.util.WifiPermissionsUtil;
+
+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 BroadcastReceiver mLocationModeReceiver;
+
+ 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;
+
+ @Mock
+ FrameworkFacade mFrameworkFacade;
+
+ /**
+ * 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();
+ doNothing().when(mFrameworkFacade).registerContentObserver(eq(mockContext), any(),
+ anyBoolean(), any());
+ when(mFrameworkFacade.getSecureIntegerSetting(any(), eq(Settings.Secure.LOCATION_MODE),
+ anyInt())).thenReturn(Settings.Secure.LOCATION_MODE_HIGH_ACCURACY);
+ 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, mFrameworkFacade);
+ mMockLooper.dispatchAll();
+ ArgumentCaptor<BroadcastReceiver> bcastRxCaptor = ArgumentCaptor.forClass(
+ BroadcastReceiver.class);
+ verify(mockContext, times(2)).registerReceiver(bcastRxCaptor.capture(),
+ any(IntentFilter.class));
+ verify(mockNative).start();
+ mPowerBcastReceiver = bcastRxCaptor.getAllValues().get(0);
+ mLocationModeReceiver = bcastRxCaptor.getAllValues().get(1);
+
+ 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, MacAddress> peerHandleToMacMap = new HashMap<>();
+ MacAddress macAwarePeer1 = MacAddress.fromString("AA:BB:CC:DD:EE:FF");
+ MacAddress macAwarePeer2 = MacAddress.fromString("BB:BB:BB:EE:EE:EE");
+ 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(MacAddress.fromString("00:01:02:03:04:00").toByteArray(),
+ (byte[]) mListCaptor.getValue().get(0));
+ assertArrayEquals(MacAddress.fromString("0A:0B:0C:0D:0E:00").toByteArray(),
+ (byte[]) mListCaptor.getValue().get(1));
+ assertArrayEquals(MacAddress.fromString("08:09:08:07:06:05").toByteArray(),
+ (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(FAILURE_MODE_DISABLE_WIFI);
+ }
+
+ /**
+ * Validate that when Doze mode starts, RTT gets disabled and the ranging queue gets cleared.
+ */
+ @Test
+ public void testDozeModeFlow() throws Exception {
+ runDisableRttFlow(FAILURE_MODE_ENABLE_DOZE);
+ }
+
+ /**
+ * Validate that when locationing is disabled, RTT gets disabled and the ranging queue gets
+ * cleared.
+ */
+ @Test
+ public void testLocationingOffFlow() throws Exception {
+ runDisableRttFlow(FAILURE_MODE_DISABLE_LOCATIONING);
+ }
+
+
+ private static final int FAILURE_MODE_DISABLE_WIFI = 0;
+ private static final int FAILURE_MODE_ENABLE_DOZE = 1;
+ private static final int FAILURE_MODE_DISABLE_LOCATIONING = 2;
+
+ /**
+ * Actually execute the disable RTT flow: either by disabling Wi-Fi or enabling doze.
+ *
+ * @param failureMode The mechanism by which RTT is to be disabled. One of the FAILURE_MODE_*
+ * constants above.
+ */
+ private void runDisableRttFlow(int failureMode) 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 (failureMode == FAILURE_MODE_DISABLE_WIFI) {
+ when(mockNative.isReady()).thenReturn(false);
+ mDut.disable();
+ } else if (failureMode == FAILURE_MODE_ENABLE_DOZE) {
+ simulatePowerStateChangeDoze(true);
+ } else if (failureMode == FAILURE_MODE_DISABLE_LOCATIONING) {
+ when(mFrameworkFacade.getSecureIntegerSetting(any(), eq(Settings.Secure.LOCATION_MODE),
+ anyInt())).thenReturn(Settings.Secure.LOCATION_MODE_OFF);
+ simulateLocationModeChange();
+ }
+ 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 (failureMode == FAILURE_MODE_DISABLE_WIFI) {
+ when(mockNative.isReady()).thenReturn(true);
+ mDut.enableIfPossible();
+ } else if (failureMode == FAILURE_MODE_ENABLE_DOZE) {
+ simulatePowerStateChangeDoze(false);
+ } else if (failureMode == FAILURE_MODE_DISABLE_LOCATIONING) {
+ when(mFrameworkFacade.getSecureIntegerSetting(any(), eq(Settings.Secure.LOCATION_MODE),
+ anyInt())).thenReturn(Settings.Secure.LOCATION_MODE_HIGH_ACCURACY);
+ simulateLocationModeChange();
+ }
+ 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);
+ }
+
+ /**
+ * Simulate the broadcast which is dispatched when a LOCATION_MODE is modified.
+ */
+ private void simulateLocationModeChange() {
+ Intent intent = new Intent(LocationManager.MODE_CHANGED_ACTION);
+ mLocationModeReceiver.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, MacAddress> mPeerIdToMacMap;
+
+ AwareTranslatePeerHandlesToMac(int expectedUid, Map<Integer, MacAddress> 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).toByteArray();
+ 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..ec56322
--- /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.MacAddress;
+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 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);
+ MacAddress mac1 = MacAddress.fromString("08:09:08:07:06:05");
+
+ 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,
+ MacAddress.fromString("10:01:02:03:04:05"), rangeCmBase++,
+ rangeStdDevCmBase++, rssiBase++, rangeTimestampBase++));
+ results.add(new RangingResult(RangingResult.STATUS_SUCCESS,
+ MacAddress.fromString("1A:0B:0C:0D:0E:0F"), rangeCmBase++,
+ rangeStdDevCmBase++, rssiBase++, rangeTimestampBase++));
+ results.add(new RangingResult(RangingResult.STATUS_SUCCESS,
+ MacAddress.fromString("08:09:08:07:06:05"), 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,
+ MacAddress overrideMac) {
+ RttResult rttResult = new RttResult();
+ rttResult.status = rangingResult.getStatus() == RangingResult.STATUS_SUCCESS
+ ? RttStatus.SUCCESS : RttStatus.FAILURE;
+ System.arraycopy(overrideMac == null ? rangingResult.getMacAddress().toByteArray()
+ : overrideMac.toByteArray(), 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 c5dce7a..9cb2992 100644
--- a/tests/wifitests/src/com/android/server/wifi/scanner/WifiScanningServiceTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/scanner/WifiScanningServiceTest.java
@@ -16,6 +16,8 @@
package com.android.server.wifi.scanner;
+import static android.content.pm.PackageManager.PERMISSION_DENIED;
+
import static com.android.server.wifi.ScanTestUtil.NativeScanSettingsBuilder;
import static com.android.server.wifi.ScanTestUtil.assertNativePnoSettingsEquals;
import static com.android.server.wifi.ScanTestUtil.assertNativeScanSettingsEquals;
@@ -46,6 +48,7 @@
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
+import android.Manifest;
import android.app.test.MockAnswerUtil.AnswerWithArguments;
import android.app.test.TestAlarmManager;
import android.content.BroadcastReceiver;
@@ -97,7 +100,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;
@@ -649,6 +651,122 @@
}
/**
+ * Do a single scan from a non-privileged app with some privileged params set.
+ * Expect a scan failure.
+ */
+ @Test
+ public void sendSingleScanRequestWithPrivilegedTypeParamsSetFromNonPrivilegedApp()
+ throws Exception {
+ WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, 0,
+ 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
+ int requestId = 33;
+ requestSettings.type = WifiScanner.TYPE_HIGH_ACCURACY;
+ WorkSource workSource = new WorkSource(Binder.getCallingUid()); // don't explicitly set
+
+ when(mContext.checkPermission(
+ Manifest.permission.NETWORK_STACK, -1, Binder.getCallingUid()))
+ .thenReturn(PERMISSION_DENIED);
+
+ startServiceAndLoadDriver();
+ mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog);
+
+ Handler handler = mock(Handler.class);
+ BidirectionalAsyncChannel controlChannel = connectChannel(handler);
+ InOrder order = inOrder(handler, mWifiScannerImpl);
+
+ // successful start
+ when(mWifiScannerImpl.startSingleScan(any(WifiNative.ScanSettings.class),
+ any(WifiNative.ScanEventHandler.class))).thenReturn(true);
+
+ sendSingleScanRequest(controlChannel, requestId, requestSettings, null);
+
+ // Scan is successfully queued
+ mLooper.dispatchAll();
+
+ // but then fails to execute
+ verifyFailedResponse(order, handler, requestId,
+ WifiScanner.REASON_INVALID_REQUEST, "bad request");
+ assertDumpContainsCallbackLog("singleScanInvalidRequest", requestId,
+ "bad request");
+
+ assertEquals(mWifiMetrics.getOneshotScanCount(), 1);
+ assertEquals(mWifiMetrics.getScanReturnEntry(
+ WifiMetricsProto.WifiLog.SCAN_FAILURE_INVALID_CONFIGURATION), 1);
+
+ // Ensure that no scan was triggered to the lower layers.
+ verify(mBatteryStats, never()).noteWifiScanStoppedFromSource(eq(workSource));
+ verify(mWifiScannerImpl, never()).startSingleScan(any(WifiNative.ScanSettings.class),
+ any(WifiNative.ScanEventHandler.class));
+ }
+
+ /**
+ * Do a single scan from a non-privileged app with some privileged params set.
+ * Expect a scan failure.
+ */
+ @Test
+ public void sendSingleScanRequestWithPrivilegedHiddenNetworkParamsSetFromNonPrivilegedApp()
+ throws Exception {
+ WifiScanner.ScanSettings requestSettings = createRequest(WifiScanner.WIFI_BAND_BOTH, 0,
+ 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
+ int requestId = 33;
+ requestSettings.hiddenNetworks = new WifiScanner.ScanSettings.HiddenNetwork[] {
+ new WifiScanner.ScanSettings.HiddenNetwork("Test1"),
+ new WifiScanner.ScanSettings.HiddenNetwork("Test2")
+ };
+ WorkSource workSource = new WorkSource(Binder.getCallingUid()); // don't explicitly set
+
+ when(mContext.checkPermission(
+ Manifest.permission.NETWORK_STACK, -1, Binder.getCallingUid()))
+ .thenReturn(PERMISSION_DENIED);
+
+ startServiceAndLoadDriver();
+ mWifiScanningServiceImpl.setWifiHandlerLogForTest(mLog);
+
+ Handler handler = mock(Handler.class);
+ BidirectionalAsyncChannel controlChannel = connectChannel(handler);
+ InOrder order = inOrder(handler, mWifiScannerImpl);
+
+ // successful start
+ when(mWifiScannerImpl.startSingleScan(any(WifiNative.ScanSettings.class),
+ any(WifiNative.ScanEventHandler.class))).thenReturn(true);
+
+ sendSingleScanRequest(controlChannel, requestId, requestSettings, null);
+
+ // Scan is successfully queued
+ mLooper.dispatchAll();
+
+ // but then fails to execute
+ verifyFailedResponse(order, handler, requestId,
+ WifiScanner.REASON_INVALID_REQUEST, "bad request");
+ assertDumpContainsCallbackLog("singleScanInvalidRequest", requestId,
+ "bad request");
+
+ assertEquals(mWifiMetrics.getOneshotScanCount(), 1);
+ assertEquals(mWifiMetrics.getScanReturnEntry(
+ WifiMetricsProto.WifiLog.SCAN_FAILURE_INVALID_CONFIGURATION), 1);
+
+ // Ensure that no scan was triggered to the lower layers.
+ verify(mBatteryStats, never()).noteWifiScanStoppedFromSource(eq(workSource));
+ verify(mWifiScannerImpl, never()).startSingleScan(any(WifiNative.ScanSettings.class),
+ any(WifiNative.ScanEventHandler.class));
+ }
+
+ /**
+ * Do a single scan from a non-privileged app with no privileged params set.
+ */
+ @Test
+ public void sendSingleScanRequestWithNoPrivilegedParamsSetFromNonPrivilegedApp()
+ throws Exception {
+ when(mContext.checkPermission(
+ Manifest.permission.NETWORK_STACK, -1, Binder.getCallingUid()))
+ .thenReturn(PERMISSION_DENIED);
+ WifiScanner.ScanSettings requestSettings = createRequest(channelsToSpec(2400, 5150, 5175),
+ 0, 0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
+ doSuccessfulSingleScan(requestSettings, computeSingleScanNativeSettings(requestSettings),
+ ScanResults.create(0, 2400, 5150, 5175));
+ }
+
+ /**
* Do a single scan, which the hardware fails to start, and verify that a failure response is
* delivered.
*/
@@ -981,7 +1099,10 @@
WifiScanner.ScanSettings requestSettings3 = createRequest(channelsToSpec(5150), 0,
0, 20, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN);
int requestId3 = 15;
- WorkSource workSource3 = new WorkSource(2292);
+ // Let one of the WorkSources be a chained workSource.
+ WorkSource workSource3 = new WorkSource();
+ workSource3.createWorkChain()
+ .addNode(2292, "tag1");
ScanResults results3 = ScanResults.create(0, false, 5150, 5150, 5150, 5150);
WifiNative.ScanSettings nativeSettings2and3 = createSingleScanNativeSettingsForChannels(
@@ -1766,21 +1887,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 {
@@ -1876,10 +1982,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);
@@ -1890,47 +1995,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.
@@ -1951,88 +2015,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..15dfccc 100644
--- a/tests/wifitests/src/com/android/server/wifi/scanner/WificondPnoScannerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/scanner/WificondPnoScannerTest.java
@@ -17,7 +17,7 @@
package com.android.server.wifi.scanner;
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.*;
@@ -44,7 +44,6 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import java.util.Arrays;
import java.util.Set;
/**
@@ -71,6 +70,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());
@@ -98,119 +102,6 @@
}
/**
- * Verify that we pause & resume HW PNO scan when a single scan is scheduled and invokes the
- * OnPnoNetworkFound callback when the scan results are received.
- */
- @Test
- public void pauseResumeHwDisconnectedPnoScanForSingleScan() {
- createScannerWithHwPnoScanSupport();
-
- 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);
-
- InOrder order = inOrder(eventHandler, mWifiNative);
- // Start PNO scan
- startSuccessfulPnoScan(null, pnoSettings, null, pnoEventHandler);
- // Start single scan
- assertTrue(mScanner.startSingleScan(settings, eventHandler));
- // Verify that the PNO scan was paused and single scan runs successfully
- expectSuccessfulSingleScanWithHwPnoEnabled(order, eventHandler,
- expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ), scanResults);
- verifyNoMoreInteractions(eventHandler);
-
- order = inOrder(pnoEventHandler, mWifiNative);
- // Resume PNO scan after the single scan results are received and PNO monitor debounce
- // alarm fires.
- assertTrue("dispatch pno monitor alarm",
- mAlarmManager.dispatch(
- WificondScannerImpl.HwPnoDebouncer.PNO_DEBOUNCER_ALARM_TAG));
- assertEquals("dispatch message after alarm", 1, mLooper.dispatchAll());
- // Now verify that PNO scan is resumed successfully
- expectSuccessfulHwDisconnectedPnoScan(order, pnoSettings, pnoEventHandler, scanResults);
- verifyNoMoreInteractions(pnoEventHandler);
- }
-
- /**
- * 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.
- * 3. Fail the PNO scan resume and verify that the OnPnoScanFailed callback is invoked.
- * 4. Now restart a new PNO scan to ensure that the failure was cleanly handled.
- */
- @Test
- public void delayedHwDisconnectedPnoScanFailure() {
- createScannerWithHwPnoScanSupport();
-
- 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);
-
- InOrder order = inOrder(eventHandler, mWifiNative);
- // Start PNO scan
- startSuccessfulPnoScan(null, pnoSettings, null, pnoEventHandler);
- // Start single scan
- assertTrue(mScanner.startSingleScan(settings, eventHandler));
- // Verify that the PNO scan was paused and single scan runs successfully
- expectSuccessfulSingleScanWithHwPnoEnabled(order, eventHandler,
- expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ), scanResults);
- verifyNoMoreInteractions(eventHandler);
-
- // Fail the PNO resume and check that the OnPnoScanFailed callback is invoked.
- order = inOrder(pnoEventHandler, mWifiNative);
- when(mWifiNative.startPnoScan(any(WifiNative.PnoSettings.class))).thenReturn(false);
- assertTrue("dispatch pno monitor alarm",
- mAlarmManager.dispatch(
- WificondScannerImpl.HwPnoDebouncer.PNO_DEBOUNCER_ALARM_TAG));
- assertEquals("dispatch message after alarm", 1, mLooper.dispatchAll());
- order.verify(pnoEventHandler).onPnoScanFailed();
- verifyNoMoreInteractions(pnoEventHandler);
-
- // Add a new PNO scan request
- startSuccessfulPnoScan(null, pnoSettings, null, pnoEventHandler);
- assertTrue("dispatch pno monitor alarm",
- mAlarmManager.dispatch(
- WificondScannerImpl.HwPnoDebouncer.PNO_DEBOUNCER_ALARM_TAG));
- assertEquals("dispatch message after alarm", 1, mLooper.dispatchAll());
- expectSuccessfulHwDisconnectedPnoScan(order, pnoSettings, pnoEventHandler, scanResults);
- verifyNoMoreInteractions(pnoEventHandler);
- }
-
- /**
* Verify that the HW PNO scan stop failure still resets the PNO scan state.
* 1. Start Hw PNO.
* 2. Stop Hw PNO scan which raises a stop command to WifiNative which is failed.
@@ -229,17 +120,11 @@
// Fail the PNO stop.
when(mWifiNative.stopPnoScan()).thenReturn(false);
assertTrue(mScanner.resetHwPnoList());
- assertTrue("dispatch pno monitor alarm",
- mAlarmManager.dispatch(
- WificondScannerImpl.HwPnoDebouncer.PNO_DEBOUNCER_ALARM_TAG));
mLooper.dispatchAll();
verify(mWifiNative).stopPnoScan();
// Add a new PNO scan request and ensure it runs successfully.
startSuccessfulPnoScan(null, pnoSettings, null, pnoEventHandler);
- assertTrue("dispatch pno monitor alarm",
- mAlarmManager.dispatch(
- WificondScannerImpl.HwPnoDebouncer.PNO_DEBOUNCER_ALARM_TAG));
mLooper.dispatchAll();
InOrder order = inOrder(pnoEventHandler, mWifiNative);
ScanResults scanResults = createDummyScanResults(false);
@@ -247,111 +132,10 @@
verifyNoMoreInteractions(pnoEventHandler);
}
- /**
- * Verify that the HW PNO scan is forcefully stopped (bypass debounce logic) and restarted when
- * settings change.
- * 1. Start Hw PNO.
- * 2. Stop Hw PNO .
- * 3. Now restart a new PNO scan with different settings.
- * 4. Ensure that the stop was issued before we start again.
- */
- @Test
- public void forceRestartHwDisconnectedPnoScanWhenSettingsChange() {
- createScannerWithHwPnoScanSupport();
-
- WifiNative.PnoEventHandler pnoEventHandler = mock(WifiNative.PnoEventHandler.class);
- WifiNative.PnoSettings pnoSettings = createDummyPnoSettings(false);
- InOrder order = inOrder(pnoEventHandler, mWifiNative);
-
- // Start PNO scan
- startSuccessfulPnoScan(null, pnoSettings, null, pnoEventHandler);
- expectHwDisconnectedPnoScanStart(order, pnoSettings);
-
- // Stop PNO now. This should trigger the debounce timer and not stop PNO.
- assertTrue(mScanner.resetHwPnoList());
- assertTrue(mAlarmManager.isPending(
- WificondScannerImpl.HwPnoDebouncer.PNO_DEBOUNCER_ALARM_TAG));
- order.verify(mWifiNative, never()).stopPnoScan();
-
- // Now restart PNO scan with an extra network in settings.
- pnoSettings.networkList =
- Arrays.copyOf(pnoSettings.networkList, pnoSettings.networkList.length + 1);
- pnoSettings.networkList[pnoSettings.networkList.length - 1] =
- createDummyPnoNetwork("ssid_pno_new");
- startSuccessfulPnoScan(null, pnoSettings, null, pnoEventHandler);
-
- // This should bypass the debounce timer and stop PNO scan immediately and then start
- // a new debounce timer for the start.
- order.verify(mWifiNative).stopPnoScan();
-
- // Trigger the debounce timer and ensure we start PNO scan again.
- mAlarmManager.dispatch(WificondScannerImpl.HwPnoDebouncer.PNO_DEBOUNCER_ALARM_TAG);
- mLooper.dispatchAll();
- order.verify(mWifiNative).startPnoScan(pnoSettings);
- }
-
- /**
- * Verify that the HW PNO scan is not forcefully stopped (bypass debounce logic) when
- * settings don't change.
- * 1. Start Hw PNO.
- * 2. Stop Hw PNO .
- * 3. Now restart a new PNO scan with same settings.
- * 4. Ensure that the stop was never issued.
- */
- @Test
- public void noForceRestartHwDisconnectedPnoScanWhenNoSettingsChange() {
- createScannerWithHwPnoScanSupport();
-
- WifiNative.PnoEventHandler pnoEventHandler = mock(WifiNative.PnoEventHandler.class);
- WifiNative.PnoSettings pnoSettings = createDummyPnoSettings(false);
- InOrder order = inOrder(pnoEventHandler, mWifiNative);
-
- // Start PNO scan
- startSuccessfulPnoScan(null, pnoSettings, null, pnoEventHandler);
- expectHwDisconnectedPnoScanStart(order, pnoSettings);
-
- // Stop PNO now. This should trigger the debounce timer and not stop PNO.
- assertTrue(mScanner.resetHwPnoList());
- assertTrue(mAlarmManager.isPending(
- WificondScannerImpl.HwPnoDebouncer.PNO_DEBOUNCER_ALARM_TAG));
- order.verify(mWifiNative, never()).stopPnoScan();
-
- // Now restart PNO scan with the same settings.
- startSuccessfulPnoScan(null, pnoSettings, null, pnoEventHandler);
-
- // Trigger the debounce timer and ensure that we neither stop/start.
- mLooper.dispatchAll();
- order.verify(mWifiNative, never()).startPnoScan(any(WifiNative.PnoSettings.class));
- 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 +153,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 +180,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) {
@@ -440,56 +220,4 @@
order.verify(eventHandler).onPnoNetworkFound(scanResults.getRawScanResults());
}
- /**
- * Verify that the single scan results were delivered and that the PNO scan was paused and
- * resumed either side of it.
- */
- private void expectSuccessfulSingleScanWithHwPnoEnabled(InOrder order,
- WifiNative.ScanEventHandler eventHandler, Set<Integer> expectedScanFreqs,
- ScanResults scanResults) {
- // Pause PNO scan first
- order.verify(mWifiNative).stopPnoScan();
-
- order.verify(mWifiNative).scan(eq(expectedScanFreqs), any(Set.class));
-
- when(mWifiNative.getPnoScanResults()).thenReturn(scanResults.getScanDetailArrayList());
- when(mWifiNative.getScanResults()).thenReturn(scanResults.getScanDetailArrayList());
-
- // Notify scan has finished
- mWifiMonitor.sendMessage(mWifiNative.getInterfaceName(), WifiMonitor.SCAN_RESULTS_EVENT);
- assertEquals("dispatch message after results event", 1, mLooper.dispatchAll());
-
- order.verify(eventHandler).onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
- 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);
}
}