Merge "Remove software pno scan support"
diff --git a/service/java/com/android/server/wifi/FrameworkFacade.java b/service/java/com/android/server/wifi/FrameworkFacade.java
index 760ee69..2c16444 100644
--- a/service/java/com/android/server/wifi/FrameworkFacade.java
+++ b/service/java/com/android/server/wifi/FrameworkFacade.java
@@ -25,7 +25,7 @@
import android.database.ContentObserver;
import android.net.TrafficStats;
import android.net.Uri;
-import android.net.ip.IpManager;
+import android.net.ip.IpClient;
import android.os.BatteryStats;
import android.os.Handler;
import android.os.IBinder;
@@ -137,9 +137,9 @@
return TrafficStats.getRxPackets(iface);
}
- public IpManager makeIpManager(
- Context context, String iface, IpManager.Callback callback) {
- return new IpManager(context, iface, callback);
+ public IpClient makeIpClient(
+ Context context, String iface, IpClient.Callback callback) {
+ return new IpClient(context, iface, callback);
}
/**
diff --git a/service/java/com/android/server/wifi/HalDeviceManager.java b/service/java/com/android/server/wifi/HalDeviceManager.java
index 7a1e8d9..0cc735a 100644
--- a/service/java/com/android/server/wifi/HalDeviceManager.java
+++ b/service/java/com/android/server/wifi/HalDeviceManager.java
@@ -35,9 +35,9 @@
import android.os.Handler;
import android.os.HwRemoteBinder;
import android.os.Looper;
-import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
+import android.util.LongSparseArray;
import android.util.MutableBoolean;
import android.util.MutableInt;
import android.util.SparseArray;
@@ -70,8 +70,12 @@
@VisibleForTesting
public static final String HAL_INSTANCE_NAME = "default";
+ private final Clock mClock;
+
// public API
- public HalDeviceManager() {
+ public HalDeviceManager(Clock clock) {
+ mClock = clock;
+
mInterfaceAvailableForRequestListeners.put(IfaceType.STA, new HashSet<>());
mInterfaceAvailableForRequestListeners.put(IfaceType.AP, new HashSet<>());
mInterfaceAvailableForRequestListeners.put(IfaceType.P2P, new HashSet<>());
@@ -98,12 +102,13 @@
* 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 a new Handler based on
+ * the current looper.
*/
- public void registerStatusListener(ManagerStatusListener listener, Looper looper) {
+ public void registerStatusListener(ManagerStatusListener listener, Handler handler) {
synchronized (mLock) {
if (!mManagerStatusListeners.add(new ManagerStatusListenerProxy(listener,
- looper == null ? Looper.myLooper() : looper))) {
+ handler == null ? new Handler(Looper.myLooper()) : handler))) {
Log.w(TAG, "registerStatusListener: duplicate registration ignored");
}
}
@@ -192,37 +197,37 @@
* @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 The Handler on which to dispatch the listener. A null implies a new Handler
+ * based on the current looper.
* @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);
+ 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);
+ 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);
+ 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);
+ Handler handler) {
+ return (IWifiNanIface) createIface(IfaceType.NAN, destroyedListener, handler);
}
/**
@@ -263,11 +268,11 @@
* 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.
+ * Listener called-back on the specified handler - or on the current looper if a null is passed.
*/
public boolean registerDestroyedListener(IWifiIface iface,
InterfaceDestroyedListener destroyedListener,
- Looper looper) {
+ Handler handler) {
String name = getName(iface);
if (DBG) Log.d(TAG, "registerDestroyedListener: iface(name)=" + name);
@@ -279,8 +284,7 @@
}
return cacheEntry.destroyedListeners.add(
- new InterfaceDestroyedListenerProxy(destroyedListener,
- looper == null ? Looper.myLooper() : looper));
+ new InterfaceDestroyedListenerProxy(destroyedListener, handler));
}
}
@@ -299,17 +303,16 @@
* @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 The Handler on which to dispatch the listener. A null implies a new Handler
+ * on the current looper.
*/
public void registerInterfaceAvailableForRequestListener(int ifaceType,
- InterfaceAvailableForRequestListener listener, Looper looper) {
+ InterfaceAvailableForRequestListener listener, Handler handler) {
if (DBG) Log.d(TAG, "registerInterfaceAvailableForRequestListener: ifaceType=" + ifaceType);
synchronized (mLock) {
mInterfaceAvailableForRequestListeners.get(ifaceType).add(
- new InterfaceAvailableForRequestListenerProxy(listener,
- looper == null ? Looper.myLooper() : looper));
+ new InterfaceAvailableForRequestListenerProxy(listener, handler));
}
WifiChipInfo[] chipInfos = getAllChipInfo();
@@ -474,12 +477,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();
}
@@ -1208,8 +1213,8 @@
private class ManagerStatusListenerProxy extends
ListenerProxy<ManagerStatusListener> {
ManagerStatusListenerProxy(ManagerStatusListener statusListener,
- Looper looper) {
- super(statusListener, looper, "ManagerStatusListenerProxy");
+ Handler handler) {
+ super(statusListener, handler, true, "ManagerStatusListenerProxy");
}
@Override
@@ -1270,7 +1275,7 @@
}
private IWifiIface createIface(int ifaceType, InterfaceDestroyedListener destroyedListener,
- Looper looper) {
+ Handler handler) {
if (DBG) Log.d(TAG, "createIface: ifaceType=" + ifaceType);
synchronized (mLock) {
@@ -1288,7 +1293,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
@@ -1300,7 +1305,7 @@
}
private IWifiIface createIfaceIfPossible(WifiChipInfo[] chipInfos, int ifaceType,
- InterfaceDestroyedListener destroyedListener, Looper looper) {
+ InterfaceDestroyedListener destroyedListener, Handler handler) {
if (DBG) {
Log.d(TAG, "createIfaceIfPossible: chipInfos=" + Arrays.deepToString(chipInfos)
+ ", ifaceType=" + ifaceType);
@@ -1341,9 +1346,9 @@
cacheEntry.type = ifaceType;
if (destroyedListener != null) {
cacheEntry.destroyedListeners.add(
- new InterfaceDestroyedListenerProxy(destroyedListener,
- looper == null ? Looper.myLooper() : looper));
+ new InterfaceDestroyedListenerProxy(destroyedListener, handler));
}
+ cacheEntry.creationTime = mClock.getUptimeSinceBootMillis();
if (DBG) Log.d(TAG, "createIfaceIfPossible: added cacheEntry=" + cacheEntry);
mInterfaceInfoCache.put(cacheEntry.name, cacheEntry);
@@ -1468,7 +1473,8 @@
if (isChipModeChangeProposed) {
for (int type: IFACE_TYPES_BY_PRIORITY) {
if (chipInfo.ifaces[type].length != 0) {
- if (!allowedToDeleteIfaceTypeForRequestedType(type, ifaceType)) {
+ if (!allowedToDeleteIfaceTypeForRequestedType(type, ifaceType,
+ chipInfo.ifaces[ifaceType].length != 0)) {
if (DBG) {
Log.d(TAG, "Couldn't delete existing type " + type
+ " interfaces for requested type");
@@ -1498,17 +1504,17 @@
}
if (tooManyInterfaces > 0) { // may need to delete some
- if (!allowedToDeleteIfaceTypeForRequestedType(type, ifaceType)) {
+ if (!allowedToDeleteIfaceTypeForRequestedType(type, ifaceType,
+ chipInfo.ifaces[ifaceType].length != 0)) {
if (DBG) {
Log.d(TAG, "Would need to delete some higher priority interfaces");
}
return null;
}
- // arbitrarily pick the first interfaces to delete
- for (int i = 0; i < tooManyInterfaces; ++i) {
- interfacesToBeRemovedFirst.add(chipInfo.ifaces[type][i]);
- }
+ // delete the most recently created interfaces
+ interfacesToBeRemovedFirst = selectInterfacesToDelete(tooManyInterfaces,
+ chipInfo.ifaces[type]);
}
}
@@ -1576,14 +1582,20 @@
* interface type.
*
* Rules:
- * 1. Request for AP or STA will destroy any other interface (except see #4)
+ * 1. Request for AP or STA will destroy any other interface (except see #4 and #5)
* 2. Request for P2P will destroy NAN-only
* 3. Request for NAN will not destroy any interface
* --
* 4. No interface will be destroyed for a requested interface of the same type
+ * 5. No interface will be destroyed if one of the requested interfaces already exists
*/
private boolean allowedToDeleteIfaceTypeForRequestedType(int existingIfaceType,
- int requestedIfaceType) {
+ int requestedIfaceType, boolean requestedIfaceTypeAlreadyExists) {
+ // rule 5
+ if (requestedIfaceTypeAlreadyExists) {
+ return false;
+ }
+
// rule 4
if (existingIfaceType == requestedIfaceType) {
return false;
@@ -1604,6 +1616,46 @@
}
/**
+ * Selects the interfaces to delete.
+ *
+ * Rule: select the most recently created interfaces in order.
+ *
+ * @param excessInterfaces Number of interfaces which need to be selected.
+ * @param interfaces Array of interfaces.
+ */
+ private List<WifiIfaceInfo> selectInterfacesToDelete(int excessInterfaces,
+ WifiIfaceInfo[] interfaces) {
+ if (DBG) {
+ Log.d(TAG, "selectInterfacesToDelete: excessInterfaces=" + excessInterfaces
+ + ", interfaces=" + Arrays.toString(interfaces));
+ }
+
+ boolean lookupError = false;
+ LongSparseArray<WifiIfaceInfo> orderedList = new LongSparseArray(interfaces.length);
+ for (WifiIfaceInfo info : interfaces) {
+ InterfaceCacheEntry cacheEntry = mInterfaceInfoCache.get(info.name);
+ if (cacheEntry == null) {
+ Log.e(TAG,
+ "selectInterfacesToDelete: can't find cache entry with name=" + info.name);
+ lookupError = true;
+ break;
+ }
+ orderedList.append(cacheEntry.creationTime, info);
+ }
+
+ if (lookupError) {
+ Log.e(TAG, "selectInterfacesToDelete: falling back to arbitary selection");
+ return Arrays.asList(Arrays.copyOf(interfaces, excessInterfaces));
+ } else {
+ List<WifiIfaceInfo> result = new ArrayList<>(excessInterfaces);
+ for (int i = 0; i < excessInterfaces; ++i) {
+ result.add(orderedList.valueAt(orderedList.size() - i - 1));
+ }
+ return result;
+ }
+ }
+
+ /**
* Performs chip reconfiguration per the input:
* - Removes the specified interfaces
* - Reconfigures the chip to the new chip mode (if necessary)
@@ -1850,6 +1902,7 @@
protected LISTENER mListener;
private Handler mHandler;
+ private boolean mFrontOfQueue;
// override equals & hash to make sure that the container HashSet is unique with respect to
// the contained listener
@@ -1864,37 +1917,32 @@
}
void trigger() {
- mHandler.sendMessage(mHandler.obtainMessage(LISTENER_TRIGGERED));
+ if (mFrontOfQueue) {
+ mHandler.postAtFrontOfQueue(() -> {
+ action();
+ });
+ } else {
+ mHandler.post(() -> {
+ action();
+ });
+ }
}
protected abstract void action();
- ListenerProxy(LISTENER listener, Looper looper, String tag) {
+ ListenerProxy(LISTENER listener, Handler handler, boolean frontOfQueue, 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;
+ mFrontOfQueue = frontOfQueue;
}
}
private class InterfaceDestroyedListenerProxy extends
ListenerProxy<InterfaceDestroyedListener> {
InterfaceDestroyedListenerProxy(InterfaceDestroyedListener destroyedListener,
- Looper looper) {
- super(destroyedListener, looper, "InterfaceDestroyedListenerProxy");
+ Handler handler) {
+ super(destroyedListener, handler == null ? new Handler(Looper.myLooper()) : handler,
+ true, "InterfaceDestroyedListenerProxy");
}
@Override
@@ -1906,8 +1954,9 @@
private class InterfaceAvailableForRequestListenerProxy extends
ListenerProxy<InterfaceAvailableForRequestListener> {
InterfaceAvailableForRequestListenerProxy(
- InterfaceAvailableForRequestListener destroyedListener, Looper looper) {
- super(destroyedListener, looper, "InterfaceAvailableForRequestListenerProxy");
+ InterfaceAvailableForRequestListener destroyedListener, Handler handler) {
+ super(destroyedListener, handler == null ? new Handler(Looper.myLooper()) : handler,
+ false, "InterfaceAvailableForRequestListenerProxy");
}
@Override
diff --git a/service/java/com/android/server/wifi/SoftApManager.java b/service/java/com/android/server/wifi/SoftApManager.java
index d4a1ea5..aca7a3a 100644
--- a/service/java/com/android/server/wifi/SoftApManager.java
+++ b/service/java/com/android/server/wifi/SoftApManager.java
@@ -20,6 +20,9 @@
import static com.android.server.wifi.util.ApConfigUtil.ERROR_NO_CHANNEL;
import static com.android.server.wifi.util.ApConfigUtil.SUCCESS;
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.Intent;
import android.net.InterfaceConfiguration;
import android.net.wifi.IApInterface;
import android.net.wifi.WifiConfiguration;
@@ -29,6 +32,8 @@
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
+import android.os.UserHandle;
+import android.text.TextUtils;
import android.util.Log;
import com.android.internal.util.State;
@@ -46,6 +51,8 @@
public class SoftApManager implements ActiveModeManager {
private static final String TAG = "SoftApManager";
+ private final Context mContext;
+
private final WifiNative mWifiNative;
private final String mCountryCode;
@@ -55,12 +62,14 @@
private final Listener mListener;
private final IApInterface mApInterface;
+ private final String mApInterfaceName;
private final INetworkManagementService mNwService;
private final WifiApConfigStore mWifiApConfigStore;
private final WifiMetrics mWifiMetrics;
+ private final int mMode;
private WifiConfiguration mApConfig;
/**
@@ -75,23 +84,29 @@
void onStateChanged(int state, int failureReason);
}
- public SoftApManager(Looper looper,
+ public SoftApManager(Context context,
+ Looper looper,
WifiNative wifiNative,
String countryCode,
Listener listener,
- IApInterface apInterface,
+ @NonNull IApInterface apInterface,
+ @NonNull String ifaceName,
INetworkManagementService nms,
WifiApConfigStore wifiApConfigStore,
- WifiConfiguration config,
+ @NonNull SoftApModeConfiguration apConfig,
WifiMetrics wifiMetrics) {
mStateMachine = new SoftApStateMachine(looper);
+ mContext = context;
mWifiNative = wifiNative;
mCountryCode = countryCode;
mListener = listener;
mApInterface = apInterface;
+ mApInterfaceName = ifaceName;
mNwService = nms;
mWifiApConfigStore = wifiApConfigStore;
+ mMode = apConfig.getTargetMode();
+ WifiConfiguration config = apConfig.getWifiConfiguration();
if (config == null) {
mApConfig = mWifiApConfigStore.getApConfiguration();
} else {
@@ -116,13 +131,28 @@
/**
* Update AP state.
- * @param state new AP state
+ * @param newState new AP state
+ * @param currentState current AP state
* @param reason Failure reason if the new AP state is in failure state
*/
- private void updateApState(int state, int reason) {
+ private void updateApState(int newState, int currentState, int reason) {
if (mListener != null) {
- mListener.onStateChanged(state, reason);
+ mListener.onStateChanged(newState, reason);
}
+
+ //send the AP state change broadcast
+ final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, newState);
+ intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, currentState);
+ if (newState == WifiManager.WIFI_AP_STATE_FAILED) {
+ //only set reason number when softAP start failed
+ intent.putExtra(WifiManager.EXTRA_WIFI_AP_FAILURE_REASON, reason);
+ }
+
+ intent.putExtra(WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME, mApInterfaceName);
+ intent.putExtra(WifiManager.EXTRA_WIFI_AP_MODE, mMode);
+ mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
/**
@@ -142,6 +172,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;
@@ -280,10 +311,23 @@
public boolean processMessage(Message message) {
switch (message.what) {
case CMD_START:
- updateApState(WifiManager.WIFI_AP_STATE_ENABLING, 0);
+ // 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 (!mDeathRecipient.linkToDeath(mApInterface.asBinder())) {
mDeathRecipient.unlinkToDeath();
updateApState(WifiManager.WIFI_AP_STATE_FAILED,
+ WifiManager.WIFI_AP_STATE_ENABLING,
WifiManager.SAP_START_FAILURE_GENERAL);
mWifiMetrics.incrementSoftApStartResult(
false, WifiManager.SAP_START_FAILURE_GENERAL);
@@ -291,12 +335,13 @@
}
try {
- mNetworkObserver = new NetworkObserver(mApInterface.getInterfaceName());
+ mNetworkObserver = new NetworkObserver(mApInterfaceName);
mNwService.registerObserver(mNetworkObserver);
} catch (RemoteException e) {
mDeathRecipient.unlinkToDeath();
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);
@@ -311,7 +356,9 @@
}
mDeathRecipient.unlinkToDeath();
unregisterObserver();
- updateApState(WifiManager.WIFI_AP_STATE_FAILED, failureReason);
+ updateApState(WifiManager.WIFI_AP_STATE_FAILED,
+ WifiManager.WIFI_AP_STATE_ENABLING,
+ failureReason);
mWifiMetrics.incrementSoftApStartResult(false, failureReason);
break;
}
@@ -347,7 +394,8 @@
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
@@ -359,7 +407,7 @@
mIfaceIsUp = false;
InterfaceConfiguration config = null;
try {
- config = mNwService.getInterfaceConfig(mApInterface.getInterfaceName());
+ config = mNwService.getInterfaceConfig(mApInterfaceName);
} catch (RemoteException e) {
}
if (config != null) {
@@ -383,13 +431,16 @@
break;
case CMD_AP_INTERFACE_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) {
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);
break;
@@ -399,6 +450,5 @@
return HANDLED;
}
}
-
}
}
diff --git a/service/java/com/android/server/wifi/VelocityBasedConnectedScore.java b/service/java/com/android/server/wifi/VelocityBasedConnectedScore.java
index 9d90332..69643ce 100644
--- a/service/java/com/android/server/wifi/VelocityBasedConnectedScore.java
+++ b/service/java/com/android/server/wifi/VelocityBasedConnectedScore.java
@@ -34,7 +34,8 @@
private final int mThresholdMinimumRssi24; // -85
private int mFrequency = 5000;
- private int mRssi = 0;
+ private double mThresholdMinimumRssi;
+ private double mThresholdAdjustment;
private final KalmanFilter mFilter;
private long mLastMillis;
@@ -44,6 +45,7 @@
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});
@@ -69,6 +71,7 @@
@Override
public void reset() {
mLastMillis = 0;
+ mThresholdAdjustment = 0.0;
}
/**
@@ -97,6 +100,8 @@
mFilter.predict();
mLastMillis = millis;
mFilter.update(new Matrix(1, new double[]{rssi}));
+ mFilteredRssi = mFilter.mx.get(0, 0);
+ mEstimatedRateOfRssiChange = mFilter.mx.get(1, 0);
}
/**
@@ -106,10 +111,63 @@
public void updateUsingWifiInfo(WifiInfo wifiInfo, long millis) {
int frequency = wifiInfo.getFrequency();
if (frequency != mFrequency) {
- reset(); // Probably roamed
+ mLastMillis = 0; // Probably roamed; reset filter but retain threshold adjustment
+ // Consider resetting or partially resetting threshold adjustment
+ // Consider checking bssid
mFrequency = frequency;
+ mThresholdMinimumRssi =
+ mFrequency >= 5000 ? mThresholdMinimumRssi5 : mThresholdMinimumRssi24;
}
updateUsingRssi(wifiInfo.getRssi(), millis, mDefaultRssiStandardDeviation);
+ adjustThreshold(wifiInfo);
+ }
+
+ private double mFilteredRssi;
+ private double mEstimatedRateOfRssiChange;
+
+ /**
+ * Returns the most recently computed extimate of the RSSI.
+ */
+ public double getFilteredRssi() {
+ return mFilteredRssi;
+ }
+
+ /**
+ * Returns the estimated rate of change of RSSI, in dB/second
+ */
+ public double getEstimatedRateOfRssiChange() {
+ return mEstimatedRateOfRssiChange;
+ }
+
+ /**
+ * Returns the adjusted RSSI threshold
+ */
+ public double getAdjustedRssiThreshold() {
+ return mThresholdMinimumRssi + mThresholdAdjustment;
+ }
+
+ /**
+ * Adjusts the threshold if appropriate
+ * <p>
+ * If the (filtered) rssi is near or below the current effective threshold, and the
+ * rate of rssi change is small, and there is traffic, and the error rate is looking
+ * reasonable, then decrease the effective threshold to keep from dropping a perfectly good
+ * connection.
+ *
+ */
+ private void adjustThreshold(WifiInfo wifiInfo) {
+ if (mThresholdAdjustment < -7) return;
+ if (mFilteredRssi >= getAdjustedRssiThreshold() + 2.0) return;
+ if (Math.abs(mEstimatedRateOfRssiChange) >= 0.2) return;
+ if (wifiInfo.txSuccessRate < 10) return;
+ if (wifiInfo.rxSuccessRate < 10) return;
+ double probabilityOfSuccessfulTx = (
+ wifiInfo.txSuccessRate / (wifiInfo.txSuccessRate + wifiInfo.txBadRate)
+ );
+ if (probabilityOfSuccessfulTx >= 0.2) {
+ // May want this amount to vary with how close to threshold we are
+ mThresholdAdjustment -= 0.5;
+ }
}
/**
@@ -117,7 +175,7 @@
*/
@Override
public int generateScore() {
- int badRssi = mFrequency >= 5000 ? mThresholdMinimumRssi5 : mThresholdMinimumRssi24;
+ double badRssi = getAdjustedRssiThreshold();
double horizonSeconds = 15.0;
Matrix x = new Matrix(mFilter.mx);
double filteredRssi = x.get(0, 0);
diff --git a/service/java/com/android/server/wifi/WifiConfigManager.java b/service/java/com/android/server/wifi/WifiConfigManager.java
index ba1695a..b610bd9 100644
--- a/service/java/com/android/server/wifi/WifiConfigManager.java
+++ b/service/java/com/android/server/wifi/WifiConfigManager.java
@@ -1010,7 +1010,7 @@
}
boolean newNetwork = (existingInternalConfig == null);
- // This is needed to inform IpManager about any IP configuration changes.
+ // This is needed to inform IpClient about any IP configuration changes.
boolean hasIpChanged =
newNetwork || WifiConfigurationUtil.hasIpChanged(
existingInternalConfig, newInternalConfig);
diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java
index 1cbb29e..cc55934 100644
--- a/service/java/com/android/server/wifi/WifiInjector.java
+++ b/service/java/com/android/server/wifi/WifiInjector.java
@@ -16,6 +16,7 @@
package com.android.server.wifi;
+import android.annotation.NonNull;
import android.app.ActivityManager;
import android.content.Context;
import android.net.NetworkKey;
@@ -23,7 +24,6 @@
import android.net.wifi.IApInterface;
import android.net.wifi.IWifiScanner;
import android.net.wifi.IWificond;
-import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiNetworkScoreCache;
import android.net.wifi.WifiScanner;
@@ -163,7 +163,7 @@
mWifiMetrics = new WifiMetrics(mClock, wifiStateMachineLooper, awareMetrics);
// Modules interacting with Native.
mWifiMonitor = new WifiMonitor(this);
- mHalDeviceManager = new HalDeviceManager();
+ mHalDeviceManager = new HalDeviceManager(mClock);
mWifiVendorHal =
new WifiVendorHal(mHalDeviceManager, mWifiStateMachineHandlerThread.getLooper());
mSupplicantStaIfaceHal = new SupplicantStaIfaceHal(mContext, mWifiMonitor);
@@ -370,16 +370,18 @@
* changes
* @param listener listener for SoftApManager
* @param apInterface network interface to start hostapd against
- * @param config softAp WifiConfiguration
+ * @param ifaceName name of the ap interface
+ * @param config SoftApModeConfiguration object holding the config and mode
* @return an instance of SoftApManager
*/
public SoftApManager makeSoftApManager(INetworkManagementService nmService,
SoftApManager.Listener listener,
- IApInterface apInterface,
- WifiConfiguration config) {
- return new SoftApManager(mWifiServiceHandlerThread.getLooper(),
+ @NonNull IApInterface apInterface,
+ @NonNull String ifaceName,
+ @NonNull SoftApModeConfiguration config) {
+ return new SoftApManager(mContext, mWifiServiceHandlerThread.getLooper(),
mWifiNative, mCountryCode.getCountryCode(),
- listener, apInterface, nmService,
+ listener, apInterface, ifaceName, nmService,
mWifiApConfigStore, config, mWifiMetrics);
}
diff --git a/service/java/com/android/server/wifi/WifiMetrics.java b/service/java/com/android/server/wifi/WifiMetrics.java
index 7254ad4..a8ad08c 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;
@@ -80,6 +81,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,
@@ -1055,10 +1058,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 +1074,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);
+ }
}
}
@@ -1984,6 +2005,7 @@
public void setWifiState(int wifiState) {
synchronized (mLock) {
mWifiState = wifiState;
+ mWifiWins = (wifiState == WifiMetricsProto.WifiLog.WIFI_ASSOCIATED);
}
}
@@ -2089,6 +2111,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 +2132,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 +2293,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 +2303,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 +2366,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/WifiScoreReport.java b/service/java/com/android/server/wifi/WifiScoreReport.java
index 324cdba..69d91c7 100644
--- a/service/java/com/android/server/wifi/WifiScoreReport.java
+++ b/service/java/com/android/server/wifi/WifiScoreReport.java
@@ -49,7 +49,7 @@
ConnectedScore mConnectedScore;
ConnectedScore mAggressiveConnectedScore;
- ConnectedScore mFancyConnectedScore;
+ VelocityBasedConnectedScore mFancyConnectedScore;
WifiScoreReport(Context context, WifiConfigManager wifiConfigManager, Clock clock) {
mClock = clock;
@@ -171,6 +171,8 @@
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;
@@ -180,8 +182,8 @@
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,%d",
- timestamp, mSessionNumber, rssi, freq, linkSpeed,
+ "%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, s2);
mLinkMetricsHistory.add(s);
@@ -205,7 +207,8 @@
* @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,s2");
+ pw.println("time,session,rssi,filtered_rssi,rssi_threshold,"
+ + "freq,linkspeed,tx_good,tx_retry,tx_bad,rx,s0,s1,s2");
for (String line : mLinkMetricsHistory) {
pw.println(line);
}
diff --git a/service/java/com/android/server/wifi/WifiServiceImpl.java b/service/java/com/android/server/wifi/WifiServiceImpl.java
index 7e1e4ca..dacc2d4 100644
--- a/service/java/com/android/server/wifi/WifiServiceImpl.java
+++ b/service/java/com/android/server/wifi/WifiServiceImpl.java
@@ -61,7 +61,7 @@
import android.net.NetworkUtils;
import android.net.StaticIpConfiguration;
import android.net.Uri;
-import android.net.ip.IpManager;
+import android.net.ip.IpClient;
import android.net.wifi.IWifiManager;
import android.net.wifi.ScanResult;
import android.net.wifi.ScanSettings;
@@ -2278,11 +2278,11 @@
// WifiMetrics proto bytes were requested. Dump only these.
mWifiStateMachine.updateWifiMetrics();
mWifiMetrics.dump(fd, pw, args);
- } else if (args != null && args.length > 0 && IpManager.DUMP_ARG.equals(args[0])) {
- // IpManager dump was requested. Pass it along and take no further action.
- String[] ipManagerArgs = new String[args.length - 1];
- System.arraycopy(args, 1, ipManagerArgs, 0, ipManagerArgs.length);
- mWifiStateMachine.dumpIpManager(fd, pw, ipManagerArgs);
+ } else if (args != null && args.length > 0 && IpClient.DUMP_ARG.equals(args[0])) {
+ // IpClient dump was requested. Pass it along and take no further action.
+ String[] ipClientArgs = new String[args.length - 1];
+ System.arraycopy(args, 1, ipClientArgs, 0, ipClientArgs.length);
+ mWifiStateMachine.dumpIpClient(fd, pw, ipClientArgs);
} else if (args != null && args.length > 0 && WifiScoreReport.DUMP_ARG.equals(args[0])) {
WifiScoreReport wifiScoreReport = mWifiStateMachine.getWifiScoreReport();
if (wifiScoreReport != null) wifiScoreReport.dump(fd, pw, args);
diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java
index b7152ac..76b78bb 100644
--- a/service/java/com/android/server/wifi/WifiStateMachine.java
+++ b/service/java/com/android/server/wifi/WifiStateMachine.java
@@ -59,7 +59,7 @@
import android.net.StaticIpConfiguration;
import android.net.TrafficStats;
import android.net.dhcp.DhcpClient;
-import android.net.ip.IpManager;
+import android.net.ip.IpClient;
import android.net.wifi.IApInterface;
import android.net.wifi.IClientInterface;
import android.net.wifi.RssiPacketCountInfo;
@@ -447,7 +447,7 @@
return true;
}
- private final IpManager mIpManager;
+ private final IpClient mIpClient;
// Channel for sending replies.
private AsyncChannel mReplyChannel = new AsyncChannel();
@@ -705,7 +705,7 @@
static final int CMD_GET_ALL_MATCHING_CONFIGS = BASE + 168;
/**
- * Used to handle messages bounced between WifiStateMachine and IpManager.
+ * Used to handle messages bounced between WifiStateMachine and IpClient.
*/
static final int CMD_IPV4_PROVISIONING_SUCCESS = BASE + 200;
static final int CMD_IPV4_PROVISIONING_FAILURE = BASE + 201;
@@ -959,8 +959,8 @@
mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
mLastSignalLevel = -1;
- mIpManager = mFacade.makeIpManager(mContext, mInterfaceName, new IpManagerCallback());
- mIpManager.setMulticastFilter(true);
+ mIpClient = mFacade.makeIpClient(mContext, mInterfaceName, new IpClientCallback());
+ mIpClient.setMulticastFilter(true);
mNoNetworksPeriodicScan = mContext.getResources().getInteger(
R.integer.config_wifi_no_network_periodic_scan_interval);
@@ -982,6 +982,7 @@
mNetworkCapabilitiesFilter.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
mNetworkCapabilitiesFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
mNetworkCapabilitiesFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
+ mNetworkCapabilitiesFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
mNetworkCapabilitiesFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
mNetworkCapabilitiesFilter.setLinkUpstreamBandwidthKbps(1024 * 1024);
mNetworkCapabilitiesFilter.setLinkDownstreamBandwidthKbps(1024 * 1024);
@@ -1139,7 +1140,7 @@
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
- class IpManagerCallback extends IpManager.Callback {
+ class IpClientCallback extends IpClient.Callback {
@Override
public void onPreDhcpAction() {
sendMessage(DhcpClient.CMD_PRE_DHCP_ACTION);
@@ -1202,10 +1203,10 @@
}
}
- private void stopIpManager() {
+ private void stopIpClient() {
/* Restore power save and suspend optimizations */
handlePostDhcpSetup();
- mIpManager.stop();
+ mIpClient.stop();
}
PendingIntent getPrivateBroadcast(String action, int requestCode) {
@@ -2109,14 +2110,14 @@
* Start filtering Multicast v4 packets
*/
public void startFilteringMulticastPackets() {
- mIpManager.setMulticastFilter(true);
+ mIpClient.setMulticastFilter(true);
}
/**
* Stop filtering Multicast v4 packets
*/
public void stopFilteringMulticastPackets() {
- mIpManager.setMulticastFilter(false);
+ mIpClient.setMulticastFilter(false);
}
/**
@@ -2232,8 +2233,8 @@
}
}
- public void dumpIpManager(FileDescriptor fd, PrintWriter pw, String[] args) {
- mIpManager.dump(fd, pw, args);
+ public void dumpIpClient(FileDescriptor fd, PrintWriter pw, String[] args) {
+ mIpClient.dump(fd, pw, args);
}
@Override
@@ -2280,7 +2281,7 @@
pw.println();
mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_USER_ACTION);
mWifiDiagnostics.dump(fd, pw, args);
- dumpIpManager(fd, pw, args);
+ dumpIpClient(fd, pw, args);
if (mWifiConnectivityManager != null) {
mWifiConnectivityManager.dump(fd, pw, args);
} else {
@@ -2925,23 +2926,6 @@
mWifiApState.set(wifiApState);
if (mVerboseLoggingEnabled) log("setWifiApState: " + syncGetWifiApStateByName());
-
- final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
- intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, wifiApState);
- intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, previousWifiApState);
- if (wifiApState == WifiManager.WIFI_AP_STATE_FAILED) {
- //only set reason number when softAP start failed
- intent.putExtra(WifiManager.EXTRA_WIFI_AP_FAILURE_REASON, reason);
- }
-
- if (ifaceName == null) {
- loge("Updating wifiApState with a null iface name");
- }
- intent.putExtra(WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME, ifaceName);
- intent.putExtra(WifiManager.EXTRA_WIFI_AP_MODE, mode);
-
- mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
private void setScanResults() {
@@ -3066,7 +3050,7 @@
log("Link configuration changed for netId: " + mLastNetworkId
+ " old: " + mLinkProperties + " new: " + newLp);
}
- // We own this instance of LinkProperties because IpManager passes us a copy.
+ // We own this instance of LinkProperties because IpClient passes us a copy.
mLinkProperties = newLp;
if (mNetworkAgent != null) {
mNetworkAgent.sendLinkProperties(mLinkProperties);
@@ -3096,7 +3080,7 @@
*/
private void clearLinkProperties() {
// Clear the link properties obtained from DHCP. The only caller of this
- // function has already called IpManager#stop(), which clears its state.
+ // function has already called IpClient#stop(), which clears its state.
synchronized (mDhcpResultsLock) {
if (mDhcpResults != null) {
mDhcpResults.clear();
@@ -3322,7 +3306,7 @@
clearTargetBssid("handleNetworkDisconnect");
- stopIpManager();
+ stopIpClient();
/* Reset data structures */
mWifiScoreReport.reset();
@@ -3453,7 +3437,7 @@
// short in two ways:
// - at the time of the CMD_IP_CONFIGURATION_SUCCESSFUL event, we don't know if we
// actually have ARP reachability. it might be better to wait until the wifi
- // network has been validated by IpManager.
+ // network has been validated by IpClient.
// - in the case of a roaming event (intra-SSID), we probably trigger when L2 is
// complete.
//
@@ -4378,7 +4362,7 @@
// Disable legacy multicast filtering, which on some chipsets defaults to enabled.
// Legacy IPv6 multicast filtering blocks ICMPv6 router advertisements which breaks IPv6
// provisioning. Legacy IPv4 multicast filtering may be re-enabled later via
- // IpManager.Callback.setFallbackMulticastFilter()
+ // IpClient.Callback.setFallbackMulticastFilter()
mWifiNative.stopFilteringMulticastV4Packets();
mWifiNative.stopFilteringMulticastV6Packets();
@@ -5043,7 +5027,7 @@
// DNAv4/DNAv6 -style probing for on-link neighbors of
// interest (e.g. routers); harmless if none are configured.
if (state == SupplicantState.COMPLETED) {
- mIpManager.confirmConfiguration();
+ mIpClient.confirmConfiguration();
}
break;
case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST:
@@ -5314,7 +5298,7 @@
} else {
if (result.hasProxyChanged()) {
log("Reconfiguring proxy on connection");
- mIpManager.setHttpProxy(
+ mIpClient.setHttpProxy(
getCurrentWifiConfiguration().getHttpProxy());
}
if (result.hasIpChanged()) {
@@ -5783,7 +5767,7 @@
@Override
public void exit() {
- mIpManager.stop();
+ mIpClient.stop();
// This is handled by receiving a NETWORK_DISCONNECTION_EVENT in ConnectModeState
// Bug: 15347363
@@ -5813,17 +5797,17 @@
handlePreDhcpSetup();
break;
case DhcpClient.CMD_PRE_DHCP_ACTION_COMPLETE:
- mIpManager.completedPreDhcpAction();
+ mIpClient.completedPreDhcpAction();
break;
case DhcpClient.CMD_POST_DHCP_ACTION:
handlePostDhcpSetup();
- // We advance to mConnectedState because IpManager will also send a
+ // We advance to mConnectedState because IpClient will also send a
// CMD_IPV4_PROVISIONING_SUCCESS message, which calls handleIPv4Success(),
// which calls updateLinkProperties, which then sends
// CMD_IP_CONFIGURATION_SUCCESSFUL.
//
// In the event of failure, we transition to mDisconnectingState
- // similarly--via messages sent back from IpManager.
+ // similarly--via messages sent back from IpClient.
break;
case CMD_IPV4_PROVISIONING_SUCCESS: {
handleIPv4Success((DhcpResults) message.obj);
@@ -6065,7 +6049,7 @@
// cause the roam to fail and the device to disconnect.
clearTargetBssid("ObtainingIpAddress");
- // Stop IpManager in case we're switching from DHCP to static
+ // Stop IpClient in case we're switching from DHCP to static
// configuration or vice versa.
//
// TODO: Only ever enter this state the first time we connect to a
@@ -6075,15 +6059,15 @@
// disconnected, because DHCP might take a long time during which
// connectivity APIs such as getActiveNetworkInfo should not return
// CONNECTED.
- stopIpManager();
+ stopIpClient();
- mIpManager.setHttpProxy(currentConfig.getHttpProxy());
+ mIpClient.setHttpProxy(currentConfig.getHttpProxy());
if (!TextUtils.isEmpty(mTcpBufferSizes)) {
- mIpManager.setTcpBufferSizes(mTcpBufferSizes);
+ mIpClient.setTcpBufferSizes(mTcpBufferSizes);
}
- final IpManager.ProvisioningConfiguration prov;
+ final IpClient.ProvisioningConfiguration prov;
if (!isUsingStaticIp) {
- prov = IpManager.buildProvisioningConfiguration()
+ prov = IpClient.buildProvisioningConfiguration()
.withPreDhcpAction()
.withApfCapabilities(mWifiNative.getApfCapabilities())
.withNetwork(getCurrentNetwork())
@@ -6091,14 +6075,14 @@
.build();
} else {
StaticIpConfiguration staticIpConfig = currentConfig.getStaticIpConfiguration();
- prov = IpManager.buildProvisioningConfiguration()
+ prov = IpClient.buildProvisioningConfiguration()
.withStaticConfiguration(staticIpConfig)
.withApfCapabilities(mWifiNative.getApfCapabilities())
.withNetwork(getCurrentNetwork())
.withDisplayName(currentConfig.SSID)
.build();
}
- mIpManager.startProvisioning(prov);
+ mIpClient.startProvisioning(prov);
// Get Link layer stats so as we get fresh tx packet counters
getWifiLinkLayerStats();
}
@@ -6294,10 +6278,10 @@
// We used to transition to ObtainingIpState in an
// attempt to do DHCPv4 RENEWs on framework roams.
// DHCP can take too long to time out, and we now rely
- // upon IpManager's use of IpReachabilityMonitor to
+ // upon IpClient's use of IpReachabilityMonitor to
// confirm our current network configuration.
//
- // mIpManager.confirmConfiguration() is called within
+ // mIpClient.confirmConfiguration() is called within
// the handling of SupplicantState.COMPLETED.
transitionTo(mConnectedState);
} else {
@@ -6984,10 +6968,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;
}
@@ -6995,16 +6976,20 @@
try {
mIfaceName = apInterface.getInterfaceName();
} catch (RemoteException e) {
- // Failed to get the interface name. The name will not be available for
- // the enabled broadcast, but since we had an error getting the name, we most likely
- // won't be able to fully start softap mode.
+ // Failed to get the interface name. This is not a good sign and we should report
+ // a failure and switch back to the initial state to reset the driver and HAL.
+ setWifiApState(WIFI_AP_STATE_FAILED,
+ WifiManager.SAP_START_FAILURE_GENERAL, null, mMode);
+ transitionTo(mInitialState);
+ return;
}
checkAndSetConnectivityInstance();
mSoftApManager = mWifiInjector.makeSoftApManager(mNwService,
new SoftApListener(),
apInterface,
- config.getWifiConfiguration());
+ mIfaceName,
+ config);
mSoftApManager.start();
mWifiStateTracker.updateState(WifiStateTracker.SOFT_AP);
}
diff --git a/service/java/com/android/server/wifi/WifiStateMachinePrime.java b/service/java/com/android/server/wifi/WifiStateMachinePrime.java
index cd1948f..c49b645 100644
--- a/service/java/com/android/server/wifi/WifiStateMachinePrime.java
+++ b/service/java/com/android/server/wifi/WifiStateMachinePrime.java
@@ -16,6 +16,7 @@
package com.android.server.wifi;
+import android.annotation.NonNull;
import android.net.wifi.IApInterface;
import android.net.wifi.IWificond;
import android.net.wifi.WifiConfiguration;
@@ -50,7 +51,7 @@
private IWificond mWificond;
- private Queue<WifiConfiguration> mApConfigQueue = new ConcurrentLinkedQueue<>();
+ private Queue<SoftApModeConfiguration> mApConfigQueue = new ConcurrentLinkedQueue<>();
/* The base for wifi message types */
static final int BASE = Protocol.BASE_WIFI;
@@ -106,17 +107,13 @@
/**
* Method to enable soft ap for wifi hotspot.
*
- * The WifiConfiguration is generally going to be null to indicate that the
- * currently saved config in WifiApConfigManager should be used. When the config is
- * not null, it will be saved in the WifiApConfigManager. This save is performed in the
- * constructor of SoftApManager.
+ * The supplied SoftApModeConfiguration includes the target softap WifiConfiguration (or null if
+ * the persisted config is to be used) and the target operating mode (ex,
+ * {@link WifiManager.IFACE_IP_MODE_TETHERED} {@link WifiManager.IFACE_IP_MODE_LOCAL_ONLY}).
*
- * @param wifiConfig WifiConfiguration for the hostapd softap
+ * @param wifiConfig SoftApModeConfiguration for the hostapd softap
*/
- public void enterSoftAPMode(WifiConfiguration wifiConfig) {
- if (wifiConfig == null) {
- wifiConfig = new WifiConfiguration();
- }
+ public void enterSoftAPMode(@NonNull SoftApModeConfiguration wifiConfig) {
mApConfigQueue.offer(wifiConfig);
changeMode(ModeStateMachine.CMD_START_SOFT_AP_MODE);
}
@@ -270,6 +267,7 @@
class SoftAPModeState extends State {
IApInterface mApInterface = null;
+ String mIfaceName = null;
@Override
public void enter() {
@@ -281,23 +279,18 @@
// Continue with setup since we are changing modes
mApInterface = null;
- mWificond = mWifiInjector.makeWificond();
- if (mWificond == null) {
- Log.e(TAG, "Failed to get reference to wificond");
- writeApConfigDueToStartFailure();
- mModeStateMachine.sendMessage(CMD_START_AP_FAILURE);
- return;
- }
try {
+ mWificond = mWifiInjector.makeWificond();
mApInterface = mWificond.createApInterface(
mWifiInjector.getWifiNative().getInterfaceName());
- } catch (RemoteException e1) { }
-
- if (mApInterface == null) {
- Log.e(TAG, "Could not get IApInterface instance from wificond");
- writeApConfigDueToStartFailure();
- mModeStateMachine.sendMessage(CMD_START_AP_FAILURE);
+ mIfaceName = mApInterface.getInterfaceName();
+ } catch (RemoteException e) {
+ initializationFailed(
+ "Could not get IApInterface instance or its name from wificond");
+ return;
+ } catch (NullPointerException e) {
+ initializationFailed("wificond failure when initializing softap mode");
return;
}
mModeStateMachine.transitionTo(mSoftAPModeActiveState);
@@ -317,6 +310,8 @@
// not in active state, nothing to stop.
break;
case CMD_START_AP_FAILURE:
+ // remove the saved config for the start attempt
+ mApConfigQueue.poll();
Log.e(TAG, "Failed to start SoftApMode. Wait for next mode command.");
break;
case CMD_AP_STOPPED:
@@ -337,12 +332,13 @@
return mApInterface;
}
- private void writeApConfigDueToStartFailure() {
- WifiConfiguration config = mApConfigQueue.poll();
- if (config != null && config.SSID != null) {
- // Save valid configs for future calls.
- mWifiInjector.getWifiApConfigStore().setApConfiguration(config);
- }
+ protected String getInterfaceName() {
+ return mIfaceName;
+ }
+
+ private void initializationFailed(String message) {
+ Log.e(TAG, message);
+ mModeStateMachine.sendMessage(CMD_START_AP_FAILURE);
}
}
@@ -410,16 +406,17 @@
@Override
public void enter() {
Log.d(TAG, "Entering SoftApModeActiveState");
- WifiConfiguration config = mApConfigQueue.poll();
+ SoftApModeConfiguration softApModeConfig = mApConfigQueue.poll();
+ WifiConfiguration config = softApModeConfig.getWifiConfiguration();
+ // TODO (b/67601382): add checks for valid softap configs
if (config != null && config.SSID != null) {
Log.d(TAG, "Passing config to SoftApManager! " + config);
} else {
config = null;
}
-
this.mActiveModeManager = mWifiInjector.makeSoftApManager(mNMService,
new SoftApListener(), ((SoftAPModeState) mSoftAPModeState).getInterface(),
- config);
+ ((SoftAPModeState) mSoftAPModeState).getInterfaceName(), softApModeConfig);
mActiveModeManager.start();
}
diff --git a/service/java/com/android/server/wifi/WifiVendorHal.java b/service/java/com/android/server/wifi/WifiVendorHal.java
index cec36a5..2d8d286 100644
--- a/service/java/com/android/server/wifi/WifiVendorHal.java
+++ b/service/java/com/android/server/wifi/WifiVendorHal.java
@@ -249,7 +249,8 @@
public boolean initialize(WifiNative.VendorHalDeathEventHandler handler) {
synchronized (sLock) {
mHalDeviceManager.initialize();
- mHalDeviceManager.registerStatusListener(mHalDeviceManagerStatusCallbacks, mLooper);
+ mHalDeviceManager.registerStatusListener(mHalDeviceManagerStatusCallbacks,
+ mHalEventHandler);
mDeathEventHandler = handler;
return true;
}
diff --git a/service/java/com/android/server/wifi/aware/WifiAwareNativeManager.java b/service/java/com/android/server/wifi/aware/WifiAwareNativeManager.java
index e855d81..8659a77 100644
--- a/service/java/com/android/server/wifi/aware/WifiAwareNativeManager.java
+++ b/service/java/com/android/server/wifi/aware/WifiAwareNativeManager.java
@@ -20,6 +20,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 android.os.RemoteException;
import android.util.Log;
@@ -41,6 +42,7 @@
private WifiAwareStateManager mWifiAwareStateManager;
private HalDeviceManager mHalDeviceManager;
+ private Handler mHandler;
private WifiAwareNativeCallback mWifiAwareNativeCallback;
private IWifiNanIface mWifiNanIface = null;
private InterfaceDestroyedListener mInterfaceDestroyedListener =
@@ -56,7 +58,13 @@
mWifiAwareNativeCallback = wifiAwareNativeCallback;
}
- public void start() {
+ /**
+ * Initialize the class - intended for late initialization.
+ *
+ * @param handler Handler on which to execute interface available callbacks.
+ */
+ public void start(Handler handler) {
+ mHandler = handler;
mHalDeviceManager.initialize();
mHalDeviceManager.registerStatusListener(
new HalDeviceManager.ManagerStatusListener() {
@@ -69,7 +77,7 @@
// 1. no problem registering duplicates - only one will be called
// 2. will be called immediately if available
mHalDeviceManager.registerInterfaceAvailableForRequestListener(
- IfaceType.NAN, mInterfaceAvailableForRequestListener, null);
+ IfaceType.NAN, mInterfaceAvailableForRequestListener, mHandler);
} else {
awareIsDown();
}
@@ -77,7 +85,7 @@
}, null);
if (mHalDeviceManager.isStarted()) {
mHalDeviceManager.registerInterfaceAvailableForRequestListener(
- IfaceType.NAN, mInterfaceAvailableForRequestListener, null);
+ IfaceType.NAN, mInterfaceAvailableForRequestListener, mHandler);
tryToGetAware();
}
}
@@ -104,7 +112,7 @@
return;
}
IWifiNanIface iface = mHalDeviceManager.createNanIface(mInterfaceDestroyedListener,
- null);
+ mHandler);
if (iface == null) {
if (DBG) Log.d(TAG, "Was not able to obtain an IWifiNanIface");
} else {
diff --git a/service/java/com/android/server/wifi/aware/WifiAwareStateManager.java b/service/java/com/android/server/wifi/aware/WifiAwareStateManager.java
index 31bdff8..0efe736 100644
--- a/service/java/com/android/server/wifi/aware/WifiAwareStateManager.java
+++ b/service/java/com/android/server/wifi/aware/WifiAwareStateManager.java
@@ -1625,7 +1625,7 @@
waitForResponse = endDataPathLocal(mCurrentTransactionId, msg.arg2);
break;
case COMMAND_TYPE_DELAYED_INITIALIZATION:
- mWifiAwareNativeManager.start();
+ mWifiAwareNativeManager.start(getHandler());
waitForResponse = false;
break;
default:
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/p2p/WifiP2pServiceImpl.java b/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java
index d70ce41..da3da7c 100644
--- a/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java
+++ b/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java
@@ -32,7 +32,7 @@
import android.net.LinkProperties;
import android.net.NetworkInfo;
import android.net.NetworkUtils;
-import android.net.ip.IpManager;
+import android.net.ip.IpClient;
import android.net.wifi.WpsInfo;
import android.net.wifi.p2p.IWifiP2pManager;
import android.net.wifi.p2p.WifiP2pConfig;
@@ -113,7 +113,7 @@
private Context mContext;
INetworkManagementService mNwService;
- private IpManager mIpManager;
+ private IpClient mIpClient;
private DhcpResults mDhcpResults;
private P2pStateMachine mP2pStateMachine;
@@ -180,12 +180,12 @@
// msg.obj = StateMachine to send to when blocked
public static final int BLOCK_DISCOVERY = BASE + 15;
- // Messages for interaction with IpManager.
- private static final int IPM_PRE_DHCP_ACTION = BASE + 30;
- private static final int IPM_POST_DHCP_ACTION = BASE + 31;
- private static final int IPM_DHCP_RESULTS = BASE + 32;
- private static final int IPM_PROVISIONING_SUCCESS = BASE + 33;
- private static final int IPM_PROVISIONING_FAILURE = BASE + 34;
+ // Messages for interaction with IpClient.
+ private static final int IPC_PRE_DHCP_ACTION = BASE + 30;
+ private static final int IPC_POST_DHCP_ACTION = BASE + 31;
+ private static final int IPC_DHCP_RESULTS = BASE + 32;
+ private static final int IPC_PROVISIONING_SUCCESS = BASE + 33;
+ private static final int IPC_PROVISIONING_FAILURE = BASE + 34;
public static final int ENABLED = 1;
public static final int DISABLED = 0;
@@ -442,50 +442,50 @@
}
}
- private void stopIpManager() {
- if (mIpManager != null) {
- mIpManager.stop();
- mIpManager = null;
+ private void stopIpClient() {
+ if (mIpClient != null) {
+ mIpClient.stop();
+ mIpClient = null;
}
mDhcpResults = null;
}
- private void startIpManager(String ifname) {
- stopIpManager();
+ private void startIpClient(String ifname) {
+ stopIpClient();
- mIpManager = new IpManager(mContext, ifname,
- new IpManager.Callback() {
+ mIpClient = new IpClient(mContext, ifname,
+ new IpClient.Callback() {
@Override
public void onPreDhcpAction() {
- mP2pStateMachine.sendMessage(IPM_PRE_DHCP_ACTION);
+ mP2pStateMachine.sendMessage(IPC_PRE_DHCP_ACTION);
}
@Override
public void onPostDhcpAction() {
- mP2pStateMachine.sendMessage(IPM_POST_DHCP_ACTION);
+ mP2pStateMachine.sendMessage(IPC_POST_DHCP_ACTION);
}
@Override
public void onNewDhcpResults(DhcpResults dhcpResults) {
- mP2pStateMachine.sendMessage(IPM_DHCP_RESULTS, dhcpResults);
+ mP2pStateMachine.sendMessage(IPC_DHCP_RESULTS, dhcpResults);
}
@Override
public void onProvisioningSuccess(LinkProperties newLp) {
- mP2pStateMachine.sendMessage(IPM_PROVISIONING_SUCCESS);
+ mP2pStateMachine.sendMessage(IPC_PROVISIONING_SUCCESS);
}
@Override
public void onProvisioningFailure(LinkProperties newLp) {
- mP2pStateMachine.sendMessage(IPM_PROVISIONING_FAILURE);
+ mP2pStateMachine.sendMessage(IPC_PROVISIONING_FAILURE);
}
},
mNwService);
- final IpManager.ProvisioningConfiguration config =
- mIpManager.buildProvisioningConfiguration()
- .withoutIPv6()
- .withoutIpReachabilityMonitor()
- .withPreDhcpAction(30 * 1000)
- .withProvisioningTimeoutMs(36 * 1000)
- .build();
- mIpManager.startProvisioning(config);
+ final IpClient.ProvisioningConfiguration config =
+ mIpClient.buildProvisioningConfiguration()
+ .withoutIPv6()
+ .withoutIpReachabilityMonitor()
+ .withPreDhcpAction(30 * 1000)
+ .withProvisioningTimeoutMs(36 * 1000)
+ .build();
+ mIpClient.startProvisioning(config);
}
/**
@@ -529,7 +529,7 @@
synchronized (mLock) {
mIWifiP2pIface = null;
}
- }, mP2pStateMachine.getHandler().getLooper());
+ }, mP2pStateMachine.getHandler());
}
return messenger;
@@ -642,10 +642,10 @@
pw.println("mDeathDataByBinder " + mDeathDataByBinder);
pw.println();
- final IpManager ipManager = mIpManager;
- if (ipManager != null) {
- pw.println("mIpManager:");
- ipManager.dump(fd, pw, args);
+ final IpClient ipClient = mIpClient;
+ if (ipClient != null) {
+ pw.println("mIpClient:");
+ ipClient.dump(fd, pw, args);
}
}
@@ -945,11 +945,11 @@
case DROP_WIFI_USER_REJECT:
case GROUP_CREATING_TIMED_OUT:
case DISABLE_P2P_TIMED_OUT:
- case IPM_PRE_DHCP_ACTION:
- case IPM_POST_DHCP_ACTION:
- case IPM_DHCP_RESULTS:
- case IPM_PROVISIONING_SUCCESS:
- case IPM_PROVISIONING_FAILURE:
+ case IPC_PRE_DHCP_ACTION:
+ case IPC_POST_DHCP_ACTION:
+ case IPC_DHCP_RESULTS:
+ case IPC_PROVISIONING_SUCCESS:
+ case IPC_PROVISIONING_FAILURE:
case WifiP2pMonitor.P2P_PROV_DISC_FAILURE_EVENT:
case SET_MIRACAST_MODE:
case WifiP2pManager.START_LISTEN:
@@ -1958,7 +1958,7 @@
startDhcpServer(mGroup.getInterface());
} else {
mWifiNative.setP2pGroupIdle(mGroup.getInterface(), GROUP_IDLE_TIME_S);
- startIpManager(mGroup.getInterface());
+ startIpClient(mGroup.getInterface());
WifiP2pDevice groupOwner = mGroup.getOwner();
WifiP2pDevice peer = mPeers.get(groupOwner.deviceAddress);
if (peer != null) {
@@ -2218,17 +2218,17 @@
loge("Disconnect on unknown device: " + device);
}
break;
- case IPM_PRE_DHCP_ACTION:
+ case IPC_PRE_DHCP_ACTION:
mWifiNative.setP2pPowerSave(mGroup.getInterface(), false);
- mIpManager.completedPreDhcpAction();
+ mIpClient.completedPreDhcpAction();
break;
- case IPM_POST_DHCP_ACTION:
+ case IPC_POST_DHCP_ACTION:
mWifiNative.setP2pPowerSave(mGroup.getInterface(), true);
break;
- case IPM_DHCP_RESULTS:
+ case IPC_DHCP_RESULTS:
mDhcpResults = (DhcpResults) message.obj;
break;
- case IPM_PROVISIONING_SUCCESS:
+ case IPC_PROVISIONING_SUCCESS:
if (DBG) logd("mDhcpResults: " + mDhcpResults);
if (mDhcpResults != null) {
setWifiP2pInfoOnGroupFormation(mDhcpResults.serverAddress);
@@ -2244,7 +2244,7 @@
loge("Failed to add iface to local network " + e);
}
break;
- case IPM_PROVISIONING_FAILURE:
+ case IPC_PROVISIONING_FAILURE:
loge("IP provisioning failed");
mWifiNative.p2pGroupRemove(mGroup.getInterface());
break;
@@ -3061,8 +3061,8 @@
if (mGroup.isGroupOwner()) {
stopDhcpServer(mGroup.getInterface());
} else {
- if (DBG) logd("stop IpManager");
- stopIpManager();
+ if (DBG) logd("stop IpClient");
+ stopIpClient();
try {
mNwService.removeInterfaceFromLocalNetwork(mGroup.getInterface());
} catch (RemoteException e) {
diff --git a/service/java/com/android/server/wifi/rtt/RttNative.java b/service/java/com/android/server/wifi/rtt/RttNative.java
index f731c19..fe1829f 100644
--- a/service/java/com/android/server/wifi/rtt/RttNative.java
+++ b/service/java/com/android/server/wifi/rtt/RttNative.java
@@ -74,6 +74,15 @@
}
}
+ /**
+ * Returns true if Wi-Fi is ready for RTT requests, false otherwise.
+ */
+ public boolean isReady() {
+ synchronized (mLock) {
+ return mIWifiRttController != null;
+ }
+ }
+
private void updateController() {
if (VDBG) Log.v(TAG, "updateController: mIWifiRttController=" + mIWifiRttController);
@@ -98,6 +107,12 @@
} else {
mIWifiRttController = null;
}
+
+ if (mIWifiRttController == null) {
+ mRttService.disable();
+ } else {
+ mRttService.enable();
+ }
}
}
@@ -112,7 +127,7 @@
public boolean rangeRequest(int cmdId, RangingRequest request) {
if (VDBG) Log.v(TAG, "rangeRequest: cmdId=" + cmdId + ", request=" + request);
synchronized (mLock) {
- if (mIWifiRttController == null) {
+ if (!isReady()) {
Log.e(TAG, "rangeRequest: RttController is null");
return false;
}
@@ -149,7 +164,7 @@
public boolean rangeCancel(int cmdId, ArrayList<byte[]> macAddresses) {
if (VDBG) Log.v(TAG, "rangeCancel: cmdId=" + cmdId);
synchronized (mLock) {
- if (mIWifiRttController == null) {
+ if (!isReady()) {
Log.e(TAG, "rangeCancel: RttController is null");
return false;
}
@@ -223,12 +238,12 @@
config.mustRequestLci = false;
config.mustRequestLcr = false;
config.burstDuration = 15;
- if (config.channel.centerFreq > 5000) {
+ config.bw = halChannelBandwidthFromScanResult(scanResult.channelWidth);
+ if (config.bw == RttBw.BW_80MHZ || config.bw == RttBw.BW_160MHZ) {
config.preamble = RttPreamble.VHT;
} else {
config.preamble = RttPreamble.HT;
}
- config.bw = halChannelBandwidthFromScanResult(scanResult.channelWidth);
} catch (IllegalArgumentException e) {
Log.e(TAG, "Invalid configuration: " + e.getMessage());
continue;
diff --git a/service/java/com/android/server/wifi/rtt/RttService.java b/service/java/com/android/server/wifi/rtt/RttService.java
index 35f7615..0790dee 100644
--- a/service/java/com/android/server/wifi/rtt/RttService.java
+++ b/service/java/com/android/server/wifi/rtt/RttService.java
@@ -66,7 +66,6 @@
Context.WIFI_AWARE_SERVICE);
RttNative rttNative = new RttNative(mImpl, halDeviceManager);
- rttNative.start();
mImpl.start(handlerThread.getLooper(), awareBinder, rttNative, wifiPermissionsUtil);
}
}
diff --git a/service/java/com/android/server/wifi/rtt/RttServiceImpl.java b/service/java/com/android/server/wifi/rtt/RttServiceImpl.java
index 1921047..e6e3591 100644
--- a/service/java/com/android/server/wifi/rtt/RttServiceImpl.java
+++ b/service/java/com/android/server/wifi/rtt/RttServiceImpl.java
@@ -16,7 +16,10 @@
package com.android.server.wifi.rtt;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.hardware.wifi.V1_0.RttResult;
import android.hardware.wifi.V1_0.RttStatus;
@@ -29,12 +32,15 @@
import android.net.wifi.rtt.RangingRequest;
import android.net.wifi.rtt.RangingResult;
import android.net.wifi.rtt.RangingResultCallback;
+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.SystemClock;
+import android.os.UserHandle;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
@@ -63,7 +69,9 @@
private final Context mContext;
private IWifiAwareManager mAwareBinder;
+ private RttNative mRttNative;
private WifiPermissionsUtil mWifiPermissionsUtil;
+ private PowerManager mPowerManager;
private RttServiceSynchronized mRttServiceSynchronized;
@@ -91,8 +99,32 @@
public void start(Looper looper, IWifiAwareManager awareBinder, RttNative rttNative,
WifiPermissionsUtil wifiPermissionsUtil) {
mAwareBinder = awareBinder;
+ mRttNative = rttNative;
mWifiPermissionsUtil = wifiPermissionsUtil;
mRttServiceSynchronized = new RttServiceSynchronized(looper, rttNative);
+
+ mPowerManager = mContext.getSystemService(PowerManager.class);
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
+ mContext.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (VDBG) Log.v(TAG, "BroadcastReceiver: action=" + action);
+
+ if (PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)) {
+ if (mPowerManager.isDeviceIdleMode()) {
+ disable();
+ } else {
+ enable();
+ }
+ }
+ }
+ }, intentFilter);
+
+ mRttServiceSynchronized.mHandler.post(() -> {
+ rttNative.start();
+ });
}
/*
@@ -108,6 +140,40 @@
}
/**
+ * Enable the API: broadcast notification
+ */
+ public void enable() {
+ if (VDBG) Log.v(TAG, "enable");
+ sendRttStateChangedBroadcast(true);
+ mRttServiceSynchronized.mHandler.post(() -> {
+ // queue should be empty at this point (but this call allows validation)
+ mRttServiceSynchronized.executeNextRangingRequestIfPossible(false);
+ });
+ }
+
+ /**
+ * Disable the API:
+ * - Clean-up (fail) pending requests
+ * - Broadcast notification
+ */
+ public void disable() {
+ if (VDBG) Log.v(TAG, "disable");
+ sendRttStateChangedBroadcast(false);
+ mRttServiceSynchronized.mHandler.post(() -> {
+ mRttServiceSynchronized.cleanUpOnDisable();
+ });
+ }
+
+ /**
+ * Binder interface API to indicate whether the API is currently available. This requires an
+ * immediate asynchronous response.
+ */
+ @Override
+ public boolean isAvailable() {
+ return mRttNative.isReady() && !mPowerManager.isDeviceIdleMode();
+ }
+
+ /**
* Binder interface API to start a ranging operation. Called on binder thread, operations needs
* to be posted to handler thread.
*/
@@ -130,6 +196,15 @@
}
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 check
@@ -186,6 +261,13 @@
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(
@@ -249,6 +331,27 @@
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);
+ }
+ }
+ mRttRequestQueue.clear();
+ mRangingTimeoutMessage.cancel();
+ }
+
private void cleanUpOnClientDeath(int uid) {
if (VDBG) {
Log.v(TAG, "RttServiceSynchronized.cleanUpOnClientDeath: uid=" + uid
@@ -351,6 +454,19 @@
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 "
diff --git a/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java b/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java
index 7a25e17..30d2b40 100644
--- a/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java
@@ -51,6 +51,7 @@
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;
@@ -82,7 +83,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 +98,10 @@
private WifiStatus mStatusFail;
private class HalDeviceManagerSpy extends HalDeviceManager {
+ HalDeviceManagerSpy() {
+ super(mClock);
+ }
+
@Override
protected IWifi getWifiServiceMockable() {
return mWifiMock;
@@ -111,6 +118,7 @@
MockitoAnnotations.initMocks(this);
mTestLooper = new TestLooper();
+ mHandler = new Handler(mTestLooper.getLooper());
// initialize dummy status objects
mStatusOk = getStatus(WifiStatusCode.SUCCESS);
@@ -141,6 +149,10 @@
dumpDut("after: ");
}
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Chip Independent Tests
+ //////////////////////////////////////////////////////////////////////////////////////
+
/**
* Test basic startup flow:
* - IServiceManager registrations
@@ -196,9 +208,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,186 +286,319 @@
}
/**
- * Validate creation of STA interface from blank start-up. The remove interface.
+ * 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 testCreateStaInterfaceNoInitMode() throws Exception {
- final String name = "sta0";
-
- BaselineChip chipMock = new BaselineChip();
+ public void testCacheMismatchError() throws Exception {
+ TestChipV1 chipMock = new TestChipV1();
chipMock.initialize();
mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
mManagerStatusListenerMock);
executeAndValidateInitializationSequence();
executeAndValidateStartupSequence();
- HalDeviceManager.InterfaceDestroyedListener idl = mock(
+ HalDeviceManager.InterfaceDestroyedListener staDestroyedListener = mock(
HalDeviceManager.InterfaceDestroyedListener.class);
- HalDeviceManager.InterfaceAvailableForRequestListener iafrl = mock(
+ HalDeviceManager.InterfaceAvailableForRequestListener staAvailListener = mock(
HalDeviceManager.InterfaceAvailableForRequestListener.class);
- IWifiStaIface iface = (IWifiStaIface) validateInterfaceSequence(chipMock,
+ 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
- name, // ifaceName
- BaselineChip.STA_CHIP_MODE_ID, // finalChipMode
+ "sta0", // ifaceName
+ TestChipV1.STA_CHIP_MODE_ID, // finalChipMode
null, // tearDownList
- idl, // destroyedListener
- iafrl // availableListener
+ staDestroyedListener, // destroyedListener
+ staAvailListener // availableListener
);
- collector.checkThat("allocated interface", iface, IsNull.notNullValue());
- // act: remove interface
- mDut.removeIface(iface);
+ // Request NAN
+ IWifiIface nanIface = validateInterfaceSequence(chipMock,
+ true, // chipModeValid
+ TestChipV1.STA_CHIP_MODE_ID, // chipModeId
+ IfaceType.NAN, // ifaceTypeToCreate
+ "nan0", // ifaceName
+ TestChipV1.STA_CHIP_MODE_ID, // finalChipMode
+ null, // tearDownList
+ nanDestroyedListener, // destroyedListener
+ nanAvailListener // availableListener
+ );
+
+ // fiddle with the "chip" by removing the STA
+ chipMock.interfaceNames.get(IfaceType.STA).remove("sta0");
+
+ // now try to request another NAN
+ nanIface = mDut.createNanIface(nanDestroyedListener, mHandler);
+ mDut.registerInterfaceAvailableForRequestListener(IfaceType.NAN, nanAvailListener,
+ mHandler);
+ collector.checkThat("NAN can't be created", nanIface, IsNull.nullValue());
+
+ // verify that Wi-Fi is shut-down: should also get all onDestroyed messages that are
+ // registered (even if they seem out-of-sync to chip)
+ mTestLooper.dispatchAll();
+ verify(mWifiMock, times(2)).stop();
+ verify(mManagerStatusListenerMock, times(2)).onStatusChanged();
+ verify(staDestroyedListener).onDestroyed();
+ verify(nanDestroyedListener).onDestroyed();
+
+ verifyNoMoreInteractions(mManagerStatusListenerMock, staDestroyedListener, staAvailListener,
+ nanDestroyedListener, nanAvailListener);
+ }
+
+ /**
+ * 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 {
+ TestChipV1 chipMock = new TestChipV1();
+ chipMock.initialize();
+ mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
+ mManagerStatusListenerMock);
+ executeAndValidateInitializationSequence();
+ executeAndValidateStartupSequence();
+
+ HalDeviceManager.InterfaceAvailableForRequestListener staAvailListener = mock(
+ HalDeviceManager.InterfaceAvailableForRequestListener.class);
+
+ // get STA interface
+ IWifiIface staIface = validateInterfaceSequence(chipMock,
+ false, // chipModeValid
+ -1000, // chipModeId (only used if chipModeValid is true)
+ IfaceType.STA, // ifaceTypeToCreate
+ "sta0", // ifaceName
+ TestChipV1.STA_CHIP_MODE_ID, // finalChipMode
+ null, // tearDownList
+ null, // destroyedListener
+ null // availableListener
+ );
+ collector.checkThat("STA created", staIface, IsNull.notNullValue());
+
+ // act: register the same listener twice
+ mDut.registerInterfaceAvailableForRequestListener(IfaceType.STA, staAvailListener,
+ mHandler);
+ mDut.registerInterfaceAvailableForRequestListener(IfaceType.STA, staAvailListener,
+ mHandler);
mTestLooper.dispatchAll();
- // verify: callback triggered
- mInOrder.verify(chipMock.chip).removeStaIface(name);
- verify(idl).onDestroyed();
- verify(iafrl).onAvailableForRequest();
+ // remove STA interface -> should trigger callbacks
+ mDut.removeIface(staIface);
+ mTestLooper.dispatchAll();
- verifyNoMoreInteractions(mManagerStatusListenerMock, idl, iafrl);
+ // verify: only a single trigger
+ verify(staAvailListener).onAvailableForRequest();
+
+ verifyNoMoreInteractions(staAvailListener);
+ }
+
+ /**
+ * Validate that when no chip info is found an empty list is returned.
+ */
+ @Test
+ public void testGetSupportedIfaceTypesError() throws Exception {
+ // try API
+ Set<Integer> results = mDut.getSupportedIfaceTypes();
+
+ // verify results
+ assertEquals(0, results.size());
+ }
+
+ /**
+ * 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);
+
+ TestChipV1 chipMock = new TestChipV1();
+ chipMock.initialize();
+ mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
+ mManagerStatusListenerMock);
+ executeAndValidateInitializationSequence();
+ executeAndValidateStartupSequence(2, true);
+ }
+
+ /**
+ * 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));
+
+ TestChipV1 chipMock = new TestChipV1();
+ chipMock.initialize();
+ mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip);
+ executeAndValidateInitializationSequence();
+ executeAndValidateStartupSequence(START_HAL_RETRY_TIMES + 1, false);
+ }
+
+ /**
+ * 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));
+
+ TestChipV1 chipMock = new TestChipV1();
+ chipMock.initialize();
+ mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip);
+ executeAndValidateInitializationSequence();
+ executeAndValidateStartupSequence(1, false);
+ }
+
+ /**
+ * Validate that isSupported() returns true when IServiceManager finds the vendor HAL daemon in
+ * the VINTF.
+ */
+ @Test
+ public void testIsSupportedTrue() throws Exception {
+ mInOrder = inOrder(mServiceManagerMock, mWifiMock);
+ executeAndValidateInitializationSequence();
+ assertTrue(mDut.isSupported());
+ }
+
+ /**
+ * Validate that isSupported() returns false when IServiceManager does not find the vendor HAL
+ * daemon in the VINTF.
+ */
+ @Test
+ public void testIsSupportedFalse() throws Exception {
+ when(mServiceManagerMock.getTransport(
+ eq(IWifi.kInterfaceName), eq(HalDeviceManager.HAL_INSTANCE_NAME)))
+ .thenReturn(IServiceManager.Transport.EMPTY);
+ mInOrder = inOrder(mServiceManagerMock, mWifiMock);
+ executeAndValidateInitializationSequence(false);
+ assertFalse(mDut.isSupported());
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Chip Specific Tests - but should work on all chips!
+ // (i.e. add copies for each test chip)
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ // TestChipV1
+
+ /**
+ * Validate creation of STA interface from blank start-up. The remove interface.
+ */
+ @Test
+ public void testCreateStaInterfaceNoInitModeTestChipV1() throws Exception {
+ runCreateSingleXxxInterfaceNoInitMode(new TestChipV1(), IfaceType.STA, "sta0",
+ TestChipV1.STA_CHIP_MODE_ID, 1);
}
/**
* Validate creation of AP interface from blank start-up. The remove interface.
*/
@Test
- public void 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);
+ public void testCreateApInterfaceNoInitModeTestChipV1() throws Exception {
+ runCreateSingleXxxInterfaceNoInitMode(new TestChipV1(), IfaceType.AP, "ap0",
+ TestChipV1.AP_CHIP_MODE_ID, 1);
}
/**
* Validate creation of P2P interface from blank start-up. The remove interface.
*/
@Test
- public void 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);
+ public void testCreateP2pInterfaceNoInitModeTestChipV1() throws Exception {
+ runCreateSingleXxxInterfaceNoInitMode(new TestChipV1(), IfaceType.P2P, "p2p0",
+ TestChipV1.STA_CHIP_MODE_ID, 1);
}
/**
* Validate creation of NAN interface from blank start-up. The remove interface.
*/
@Test
- public void 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);
+ public void testCreateNanInterfaceNoInitModeTestChipV1() throws Exception {
+ runCreateSingleXxxInterfaceNoInitMode(new TestChipV1(), IfaceType.NAN, "nan0",
+ TestChipV1.STA_CHIP_MODE_ID, 1);
}
+ // TestChipV2
+
+ /**
+ * Validate creation of STA interface from blank start-up. The remove interface.
+ */
+ @Test
+ public void testCreateStaInterfaceNoInitModeTestChipV2() throws Exception {
+ // Note: we expected 2 available callbacks since we now have 2 STAs possible. So
+ // we get callback 1 after creating the first STA (since we can create another STA),
+ // and we get callback 2 after destroying the first STA (since we can create another STA -
+ // as expected).
+ runCreateSingleXxxInterfaceNoInitMode(new TestChipV2(), IfaceType.STA, "sta0",
+ TestChipV2.CHIP_MODE_ID, 2);
+ }
+
+ /**
+ * Validate creation of AP interface from blank start-up. The remove interface.
+ */
+ @Test
+ public void testCreateApInterfaceNoInitModeTestChipV2() throws Exception {
+ runCreateSingleXxxInterfaceNoInitMode(new TestChipV2(), IfaceType.AP, "ap0",
+ TestChipV2.CHIP_MODE_ID, 1);
+ }
+
+ /**
+ * Validate creation of P2P interface from blank start-up. The remove interface.
+ */
+ @Test
+ public void testCreateP2pInterfaceNoInitModeTestChipV2() throws Exception {
+ runCreateSingleXxxInterfaceNoInitMode(new TestChipV2(), IfaceType.P2P, "p2p0",
+ TestChipV2.CHIP_MODE_ID, 1);
+ }
+
+ /**
+ * Validate creation of NAN interface from blank start-up. The remove interface.
+ */
+ @Test
+ public void testCreateNanInterfaceNoInitModeTestChipV2() throws Exception {
+ runCreateSingleXxxInterfaceNoInitMode(new TestChipV2(), IfaceType.NAN, "nan0",
+ TestChipV2.CHIP_MODE_ID, 1);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // TestChipV1 Specific Tests
+ //////////////////////////////////////////////////////////////////////////////////////
+
/**
* Validate creation of AP interface when in STA mode - but with no interface created. Expect
* a change in chip mode.
*/
@Test
- public void testCreateApWithStaModeUp() throws Exception {
+ public void testCreateApWithStaModeUpTestChipV1() throws Exception {
final String name = "ap0";
- BaselineChip chipMock = new BaselineChip();
+ TestChipV1 chipMock = new TestChipV1();
chipMock.initialize();
mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
mManagerStatusListenerMock);
@@ -467,10 +612,10 @@
IWifiApIface iface = (IWifiApIface) validateInterfaceSequence(chipMock,
true, // chipModeValid
- BaselineChip.STA_CHIP_MODE_ID, // chipModeId
+ TestChipV1.STA_CHIP_MODE_ID, // chipModeId
IfaceType.AP, // ifaceTypeToCreate
name, // ifaceName
- BaselineChip.AP_CHIP_MODE_ID, // finalChipMode
+ TestChipV1.AP_CHIP_MODE_ID, // finalChipMode
null, // tearDownList
idl, // destroyedListener
iafrl // availableListener
@@ -493,10 +638,10 @@
* no change in chip mode.
*/
@Test
- public void testCreateApWithApModeUp() throws Exception {
+ public void testCreateApWithApModeUpTestChipV1() throws Exception {
final String name = "ap0";
- BaselineChip chipMock = new BaselineChip();
+ TestChipV1 chipMock = new TestChipV1();
chipMock.initialize();
mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
mManagerStatusListenerMock);
@@ -510,10 +655,10 @@
IWifiApIface iface = (IWifiApIface) validateInterfaceSequence(chipMock,
true, // chipModeValid
- BaselineChip.AP_CHIP_MODE_ID, // chipModeId
+ TestChipV1.AP_CHIP_MODE_ID, // chipModeId
IfaceType.AP, // ifaceTypeToCreate
name, // ifaceName
- BaselineChip.AP_CHIP_MODE_ID, // finalChipMode
+ TestChipV1.AP_CHIP_MODE_ID, // finalChipMode
null, // tearDownList
idl, // destroyedListener
iafrl // availableListener
@@ -550,8 +695,8 @@
* - Can create NAN when requested
*/
@Test
- public void testCreateSameAndDiffPriorities() throws Exception {
- BaselineChip chipMock = new BaselineChip();
+ public void testCreateSameAndDiffPrioritiesTestChipV1() throws Exception {
+ TestChipV1 chipMock = new TestChipV1();
chipMock.initialize();
mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
mManagerStatusListenerMock);
@@ -584,116 +729,158 @@
HalDeviceManager.InterfaceAvailableForRequestListener nanAvailListener = mock(
HalDeviceManager.InterfaceAvailableForRequestListener.class);
+ InOrder inOrderStaAvail = inOrder(staAvailListener);
+ InOrder inOrderApAvail = inOrder(apAvailListener);
+ InOrder inOrderP2pAvail = inOrder(p2pAvailListener);
+ InOrder inOrderNanAvail = inOrder(nanAvailListener);
+
+ // register listeners for interface availability
+ mDut.registerInterfaceAvailableForRequestListener(IfaceType.STA, staAvailListener,
+ mHandler);
+ mDut.registerInterfaceAvailableForRequestListener(IfaceType.AP, apAvailListener, mHandler);
+ mDut.registerInterfaceAvailableForRequestListener(IfaceType.P2P, p2pAvailListener,
+ mHandler);
+ mDut.registerInterfaceAvailableForRequestListener(IfaceType.NAN, nanAvailListener,
+ mHandler);
+ mTestLooper.dispatchAll();
+
+ inOrderStaAvail.verify(staAvailListener).onAvailableForRequest();
+ inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
+ inOrderP2pAvail.verify(p2pAvailListener).onAvailableForRequest();
+ inOrderNanAvail.verify(nanAvailListener).onAvailableForRequest();
+
// Request STA
IWifiIface staIface = validateInterfaceSequence(chipMock,
false, // chipModeValid
-1000, // chipModeId (only used if chipModeValid is true)
IfaceType.STA, // ifaceTypeToCreate
"sta0", // ifaceName
- BaselineChip.STA_CHIP_MODE_ID, // finalChipMode
+ TestChipV1.STA_CHIP_MODE_ID, // finalChipMode
null, // tearDownList
staDestroyedListener, // destroyedListener
- staAvailListener // availableListener
+ null // availableListener
);
collector.checkThat("allocated STA interface", staIface, IsNull.notNullValue());
+ inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
+ inOrderP2pAvail.verify(p2pAvailListener).onAvailableForRequest();
+ inOrderNanAvail.verify(nanAvailListener).onAvailableForRequest();
+
+ // request STA2: should fail
+ IWifiIface staIface2 = mDut.createStaIface(null, null);
+ collector.checkThat("STA2 should not be created", staIface2, IsNull.nullValue());
+
// register additional InterfaceDestroyedListeners - including a duplicate (verify that
// only called once!)
- mDut.registerDestroyedListener(staIface, staDestroyedListener2, mTestLooper.getLooper());
- mDut.registerDestroyedListener(staIface, staDestroyedListener, mTestLooper.getLooper());
+ mDut.registerDestroyedListener(staIface, staDestroyedListener2, mHandler);
+ mDut.registerDestroyedListener(staIface, staDestroyedListener, mHandler);
// Request P2P
IWifiIface p2pIface = validateInterfaceSequence(chipMock,
true, // chipModeValid
- BaselineChip.STA_CHIP_MODE_ID, // chipModeId
+ TestChipV1.STA_CHIP_MODE_ID, // chipModeId
IfaceType.P2P, // ifaceTypeToCreate
"p2p0", // ifaceName
- BaselineChip.STA_CHIP_MODE_ID, // finalChipMode
+ TestChipV1.STA_CHIP_MODE_ID, // finalChipMode
null, // tearDownList
p2pDestroyedListener, // destroyedListener
- p2pAvailListener // availableListener
+ null // availableListener
);
collector.checkThat("allocated P2P interface", p2pIface, IsNull.notNullValue());
+ inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
+
// Request AP
IWifiIface apIface = validateInterfaceSequence(chipMock,
true, // chipModeValid
- BaselineChip.STA_CHIP_MODE_ID, // chipModeId
+ TestChipV1.STA_CHIP_MODE_ID, // chipModeId
IfaceType.AP, // ifaceTypeToCreate
"ap0", // ifaceName
- BaselineChip.AP_CHIP_MODE_ID, // finalChipMode
+ TestChipV1.AP_CHIP_MODE_ID, // finalChipMode
new IWifiIface[]{staIface, p2pIface}, // tearDownList
apDestroyedListener, // destroyedListener
- apAvailListener, // availableListener
+ null, // availableListener
// destroyedInterfacesDestroyedListeners...
staDestroyedListener, staDestroyedListener2, p2pDestroyedListener
);
collector.checkThat("allocated AP interface", apIface, IsNull.notNullValue());
+ inOrderStaAvail.verify(staAvailListener).onAvailableForRequest();
+
+ // request AP2: should fail
+ IWifiIface apIface2 = mDut.createApIface(null, null);
+ collector.checkThat("AP2 should not be created", apIface2, IsNull.nullValue());
+
// Request P2P: expect failure
- p2pIface = mDut.createP2pIface(p2pDestroyedListener, mTestLooper.getLooper());
+ p2pIface = mDut.createP2pIface(p2pDestroyedListener, mHandler);
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
+ TestChipV1.AP_CHIP_MODE_ID, // chipModeId
IfaceType.STA, // ifaceTypeToCreate
"sta0", // ifaceName
- BaselineChip.STA_CHIP_MODE_ID, // finalChipMode
+ TestChipV1.STA_CHIP_MODE_ID, // finalChipMode
null, // tearDownList
staDestroyedListener, // destroyedListener
- staAvailListener, // availableListener
+ null, // availableListener
apDestroyedListener // destroyedInterfacesDestroyedListeners...
);
collector.checkThat("allocated STA interface", staIface, IsNull.notNullValue());
+ inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
+ inOrderP2pAvail.verify(p2pAvailListener).onAvailableForRequest();
+ inOrderNanAvail.verify(nanAvailListener).onAvailableForRequest();
+
mTestLooper.dispatchAll();
verify(apDestroyedListener).onDestroyed();
// Request P2P: expect success now
p2pIface = validateInterfaceSequence(chipMock,
true, // chipModeValid
- BaselineChip.STA_CHIP_MODE_ID, // chipModeId
+ TestChipV1.STA_CHIP_MODE_ID, // chipModeId
IfaceType.P2P, // ifaceTypeToCreate
"p2p0", // ifaceName
- BaselineChip.STA_CHIP_MODE_ID, // finalChipMode
+ TestChipV1.STA_CHIP_MODE_ID, // finalChipMode
null, // tearDownList
p2pDestroyedListener2, // destroyedListener
- p2pAvailListener // availableListener
+ null // availableListener
);
+ inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
+
// Request NAN: should fail
- IWifiIface nanIface = mDut.createNanIface(nanDestroyedListener, mTestLooper.getLooper());
+ IWifiIface nanIface = mDut.createNanIface(nanDestroyedListener, mHandler);
mDut.registerInterfaceAvailableForRequestListener(IfaceType.NAN, nanAvailListener,
- mTestLooper.getLooper());
+ mHandler);
collector.checkThat("NAN can't be created", nanIface, IsNull.nullValue());
// Tear down P2P
mDut.removeIface(p2pIface);
mTestLooper.dispatchAll();
+ inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
+ inOrderP2pAvail.verify(p2pAvailListener).onAvailableForRequest();
+ inOrderNanAvail.verify(nanAvailListener).onAvailableForRequest();
verify(chipMock.chip, times(2)).removeP2pIface("p2p0");
verify(p2pDestroyedListener2).onDestroyed();
// Should now be able to request and get NAN
nanIface = validateInterfaceSequence(chipMock,
true, // chipModeValid
- BaselineChip.STA_CHIP_MODE_ID, // chipModeId
+ TestChipV1.STA_CHIP_MODE_ID, // chipModeId
IfaceType.NAN, // ifaceTypeToCreate
"nan0", // ifaceName
- BaselineChip.STA_CHIP_MODE_ID, // finalChipMode
+ TestChipV1.STA_CHIP_MODE_ID, // finalChipMode
null, // tearDownList
nanDestroyedListener, // destroyedListener
nanAvailListener // availableListener
);
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();
+ inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
+ inOrderP2pAvail.verify(p2pAvailListener).onAvailableForRequest();
verifyNoMoreInteractions(mManagerStatusListenerMock, staDestroyedListener, staAvailListener,
staDestroyedListener2, apDestroyedListener, apAvailListener, p2pDestroyedListener,
@@ -713,171 +900,18 @@
* - 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.
- */
- @Test
- public void testCacheMismatchError() 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);
-
- // 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
- );
-
- // fiddle with the "chip" by removing the STA
- chipMock.interfaceNames.get(IfaceType.STA).remove("sta0");
-
- // now try to request another NAN
- nanIface = mDut.createNanIface(nanDestroyedListener, mTestLooper.getLooper());
- mDut.registerInterfaceAvailableForRequestListener(IfaceType.NAN, nanAvailListener,
- mTestLooper.getLooper());
- collector.checkThat("NAN can't be created", nanIface, IsNull.nullValue());
-
- // verify that Wi-Fi is shut-down: should also get all onDestroyed messages that are
- // registered (even if they seem out-of-sync to chip)
- mTestLooper.dispatchAll();
- verify(mWifiMock, times(2)).stop();
- verify(mManagerStatusListenerMock, times(2)).onStatusChanged();
- verify(staDestroyedListener).onDestroyed();
- verify(nanDestroyedListener).onDestroyed();
-
- verifyNoMoreInteractions(mManagerStatusListenerMock, staDestroyedListener, staAvailListener,
- nanDestroyedListener, nanAvailListener);
+ public void testP2pAndNanInteractionsTestChipV1() throws Exception {
+ runP2pAndNanExclusiveInteractionsTestChip(new TestChipV1(), false,
+ TestChipV1.STA_CHIP_MODE_ID);
}
/**
* Validates that trying to allocate a STA and then another STA fails. Only one STA at a time
- * is permitted (by baseline chip).
+ * is permitted (by TestChipV1 chip).
*/
@Test
- public void testDuplicateStaRequests() throws Exception {
- BaselineChip chipMock = new BaselineChip();
+ public void testDuplicateStaRequestsTestChipV1() throws Exception {
+ TestChipV1 chipMock = new TestChipV1();
chipMock.initialize();
mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
mManagerStatusListenerMock);
@@ -898,7 +932,7 @@
-1000, // chipModeId (only used if chipModeValid is true)
IfaceType.STA, // ifaceTypeToCreate
"sta0", // ifaceName
- BaselineChip.STA_CHIP_MODE_ID, // finalChipMode
+ TestChipV1.STA_CHIP_MODE_ID, // finalChipMode
null, // tearDownList
staDestroyedListener1, // destroyedListener
staAvailListener1 // availableListener
@@ -906,7 +940,7 @@
collector.checkThat("STA created", staIface1, IsNull.notNullValue());
// get STA interface again
- IWifiIface staIface2 = mDut.createStaIface(staDestroyedListener2, mTestLooper.getLooper());
+ IWifiIface staIface2 = mDut.createStaIface(staDestroyedListener2, mHandler);
collector.checkThat("STA created", staIface2, IsNull.nullValue());
verifyNoMoreInteractions(mManagerStatusListenerMock, staDestroyedListener1,
@@ -914,59 +948,11 @@
}
/**
- * 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.
- */
- @Test
- public void testDuplicateAvailableRegistrations() throws Exception {
- BaselineChip chipMock = new BaselineChip();
- chipMock.initialize();
- mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
- mManagerStatusListenerMock);
- executeAndValidateInitializationSequence();
- executeAndValidateStartupSequence();
-
- HalDeviceManager.InterfaceAvailableForRequestListener staAvailListener = mock(
- HalDeviceManager.InterfaceAvailableForRequestListener.class);
-
- // get STA interface
- 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
- null, // destroyedListener
- null // availableListener
- );
- collector.checkThat("STA created", staIface, IsNull.notNullValue());
-
- // act: register the same listener twice
- mDut.registerInterfaceAvailableForRequestListener(IfaceType.STA, staAvailListener,
- mTestLooper.getLooper());
- mDut.registerInterfaceAvailableForRequestListener(IfaceType.STA, staAvailListener,
- mTestLooper.getLooper());
- mTestLooper.dispatchAll();
-
- // remove STA interface -> should trigger callbacks
- mDut.removeIface(staIface);
- mTestLooper.dispatchAll();
-
- // verify: only a single trigger
- verify(staAvailListener).onAvailableForRequest();
-
- verifyNoMoreInteractions(staAvailListener);
- }
-
- /**
* Validate that the getSupportedIfaceTypes API works when requesting for all chips.
*/
@Test
- public void testGetSupportedIfaceTypesAll() throws Exception {
- BaselineChip chipMock = new BaselineChip();
+ public void testGetSupportedIfaceTypesAllTestChipV1() throws Exception {
+ TestChipV1 chipMock = new TestChipV1();
chipMock.initialize();
mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
mManagerStatusListenerMock);
@@ -990,8 +976,8 @@
* Validate that the getSupportedIfaceTypes API works when requesting for a specific chip.
*/
@Test
- public void testGetSupportedIfaceTypesOneChip() throws Exception {
- BaselineChip chipMock = new BaselineChip();
+ public void testGetSupportedIfaceTypesOneChipTestChipV1() throws Exception {
+ TestChipV1 chipMock = new TestChipV1();
chipMock.initialize();
mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
mManagerStatusListenerMock);
@@ -1011,92 +997,280 @@
assertEquals(correctResults, results);
}
- /**
- * Validate that when no chip info is found an empty list is returned.
- */
- @Test
- public void testGetSupportedIfaceTypesError() throws Exception {
- // try API
- Set<Integer> results = mDut.getSupportedIfaceTypes();
-
- // verify results
- assertEquals(0, results.size());
- }
+ //////////////////////////////////////////////////////////////////////////////////////
+ // TestChipV2 Specific Tests
+ //////////////////////////////////////////////////////////////////////////////////////
/**
- * Test start HAL can retry upon failure.
+ * 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 testStartHalRetryUponNotAvailableFailure() throws Exception {
- // Override the stubbing for mWifiMock in before().
- when(mWifiMock.start())
- .thenReturn(getStatus(WifiStatusCode.ERROR_NOT_AVAILABLE))
- .thenReturn(mStatusOk);
-
- BaselineChip chipMock = new BaselineChip();
+ public void testInterfaceCreationFlowTestChipV2() throws Exception {
+ TestChipV2 chipMock = new TestChipV2();
chipMock.initialize();
mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
mManagerStatusListenerMock);
executeAndValidateInitializationSequence();
- executeAndValidateStartupSequence(2, true);
+ executeAndValidateStartupSequence();
+
+ HalDeviceManager.InterfaceDestroyedListener staDestroyedListener = mock(
+ HalDeviceManager.InterfaceDestroyedListener.class);
+ HalDeviceManager.InterfaceDestroyedListener staDestroyedListener2 = mock(
+ HalDeviceManager.InterfaceDestroyedListener.class);
+ HalDeviceManager.InterfaceAvailableForRequestListener staAvailListener = mock(
+ HalDeviceManager.InterfaceAvailableForRequestListener.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 nanDestroyedListener = mock(
+ HalDeviceManager.InterfaceDestroyedListener.class);
+ HalDeviceManager.InterfaceAvailableForRequestListener nanAvailListener = mock(
+ HalDeviceManager.InterfaceAvailableForRequestListener.class);
+
+ InOrder inOrderStaAvail = inOrder(staAvailListener);
+ InOrder inOrderApAvail = inOrder(apAvailListener);
+ InOrder inOrderP2pAvail = inOrder(p2pAvailListener);
+ InOrder inOrderNanAvail = inOrder(nanAvailListener);
+
+ // register listeners for interface availability
+ mDut.registerInterfaceAvailableForRequestListener(IfaceType.STA, staAvailListener,
+ mHandler);
+ mDut.registerInterfaceAvailableForRequestListener(IfaceType.AP, apAvailListener, mHandler);
+ mDut.registerInterfaceAvailableForRequestListener(IfaceType.P2P, p2pAvailListener,
+ mHandler);
+ mDut.registerInterfaceAvailableForRequestListener(IfaceType.NAN, nanAvailListener,
+ mHandler);
+ mTestLooper.dispatchAll();
+
+ inOrderStaAvail.verify(staAvailListener).onAvailableForRequest();
+ inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
+ inOrderP2pAvail.verify(p2pAvailListener).onAvailableForRequest();
+ inOrderNanAvail.verify(nanAvailListener).onAvailableForRequest();
+
+ // create STA
+ when(mClock.getUptimeSinceBootMillis()).thenReturn(15L);
+ IWifiIface staIface = validateInterfaceSequence(chipMock,
+ false, // chipModeValid
+ -1000, // chipModeId (only used if chipModeValid is true)
+ IfaceType.STA, // ifaceTypeToCreate
+ "sta0", // ifaceName
+ TestChipV2.CHIP_MODE_ID, // finalChipMode
+ null, // tearDownList
+ staDestroyedListener, // destroyedListener
+ null // availableListener (already registered)
+ );
+ collector.checkThat("STA interface wasn't created", staIface, IsNull.notNullValue());
+
+ inOrderStaAvail.verify(staAvailListener).onAvailableForRequest();
+ inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
+ inOrderP2pAvail.verify(p2pAvailListener).onAvailableForRequest();
+ inOrderNanAvail.verify(nanAvailListener).onAvailableForRequest();
+
+ // create P2P
+ IWifiIface p2pIface = validateInterfaceSequence(chipMock,
+ true, // chipModeValid
+ TestChipV2.CHIP_MODE_ID, // chipModeId
+ IfaceType.P2P, // ifaceTypeToCreate
+ "p2p0", // ifaceName
+ TestChipV2.CHIP_MODE_ID, // finalChipMode
+ null, // tearDownList
+ p2pDestroyedListener, // destroyedListener
+ null // availableListener (already registered)
+ );
+ collector.checkThat("P2P interface wasn't created", p2pIface, IsNull.notNullValue());
+
+ inOrderStaAvail.verify(staAvailListener).onAvailableForRequest();
+ inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
+
+ // request NAN: should fail
+ IWifiIface nanIface = mDut.createNanIface(null, null);
+ collector.checkThat("NAN should not be created", nanIface, IsNull.nullValue());
+
+ // create AP
+ IWifiIface apIface = validateInterfaceSequence(chipMock,
+ true, // chipModeValid
+ TestChipV2.CHIP_MODE_ID, // chipModeId
+ IfaceType.AP, // ifaceTypeToCreate
+ "ap0", // ifaceName
+ TestChipV2.CHIP_MODE_ID, // finalChipMode
+ null, // tearDownList
+ apDestroyedListener, // destroyedListener
+ null // availableListener (already registered)
+ );
+ collector.checkThat("AP interface wasn't created", apIface, IsNull.notNullValue());
+
+ // request STA2: should fail
+ IWifiIface staIface2 = mDut.createStaIface(null, null);
+ collector.checkThat("STA2 should not be created", staIface2, IsNull.nullValue());
+
+ // request AP2: should fail
+ IWifiIface apIface2 = mDut.createApIface(null, null);
+ collector.checkThat("AP2 should not be created", apIface2, IsNull.nullValue());
+
+ // tear down AP
+ mDut.removeIface(apIface);
+ mTestLooper.dispatchAll();
+
+ inOrderStaAvail.verify(staAvailListener).onAvailableForRequest();
+ inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
+ verify(chipMock.chip).removeApIface("ap0");
+ verify(apDestroyedListener).onDestroyed();
+
+ // create STA2: using a later clock
+ when(mClock.getUptimeSinceBootMillis()).thenReturn(20L);
+ staIface2 = validateInterfaceSequence(chipMock,
+ true, // chipModeValid
+ TestChipV2.CHIP_MODE_ID, // chipModeId
+ IfaceType.STA, // ifaceTypeToCreate
+ "sta1", // ifaceName
+ TestChipV2.CHIP_MODE_ID, // finalChipMode
+ null, // tearDownList
+ staDestroyedListener2, // destroyedListener
+ null // availableListener (already registered)
+ );
+ collector.checkThat("STA 2 interface wasn't created", staIface2, IsNull.notNullValue());
+
+ inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
+
+ // request STA3: should fail
+ IWifiIface staIface3 = mDut.createStaIface(null, null);
+ collector.checkThat("STA3 should not be created", staIface3, IsNull.nullValue());
+
+ // create AP - this will destroy the last STA created, i.e. STA2
+ apIface = validateInterfaceSequence(chipMock,
+ true, // chipModeValid
+ TestChipV2.CHIP_MODE_ID, // chipModeId
+ IfaceType.AP, // ifaceTypeToCreate
+ "ap0", // ifaceName
+ TestChipV2.CHIP_MODE_ID, // finalChipMode
+ null, // tearDownList
+ apDestroyedListener, // destroyedListener
+ null, // availableListener (already registered),
+ staDestroyedListener2
+ );
+ collector.checkThat("AP interface wasn't created", apIface, IsNull.notNullValue());
+
+ // tear down P2P
+ mDut.removeIface(p2pIface);
+ mTestLooper.dispatchAll();
+
+ inOrderP2pAvail.verify(p2pAvailListener).onAvailableForRequest();
+ inOrderNanAvail.verify(nanAvailListener).onAvailableForRequest();
+ verify(chipMock.chip).removeP2pIface("p2p0");
+ verify(p2pDestroyedListener).onDestroyed();
+
+ // create NAN
+ nanIface = validateInterfaceSequence(chipMock,
+ true, // chipModeValid
+ TestChipV2.CHIP_MODE_ID, // chipModeId
+ IfaceType.NAN, // ifaceTypeToCreate
+ "nan0", // ifaceName
+ TestChipV2.CHIP_MODE_ID, // finalChipMode
+ null, // tearDownList
+ nanDestroyedListener, // destroyedListener
+ null // availableListener (already registered)
+ );
+ collector.checkThat("NAN interface wasn't created", nanIface, IsNull.notNullValue());
+
+ inOrderP2pAvail.verify(p2pAvailListener).onAvailableForRequest();
+
+ verifyNoMoreInteractions(mManagerStatusListenerMock, staDestroyedListener,
+ staDestroyedListener2, apDestroyedListener, p2pDestroyedListener,
+ nanDestroyedListener, staAvailListener, apAvailListener, p2pAvailListener,
+ nanAvailListener, staAvailListener, apAvailListener, p2pAvailListener,
+ nanAvailListener);
}
/**
- * Test start HAL fails after multiple retry failures.
+ * 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 testStartHalRetryFailUponMultipleNotAvailableFailures() throws Exception {
- // Override the stubbing for mWifiMock in before().
- when(mWifiMock.start()).thenReturn(getStatus(WifiStatusCode.ERROR_NOT_AVAILABLE));
+ public void testP2pAndNanInteractionsTestChipV2() throws Exception {
+ runP2pAndNanExclusiveInteractionsTestChip(new TestChipV2(), true, TestChipV2.CHIP_MODE_ID);
+ }
- BaselineChip chipMock = new BaselineChip();
+ /**
+ * 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);
+ mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
+ mManagerStatusListenerMock);
executeAndValidateInitializationSequence();
- executeAndValidateStartupSequence(START_HAL_RETRY_TIMES + 1, false);
+ 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);
}
/**
- * Test start HAL fails after multiple retry failures.
+ * Validate that the getSupportedIfaceTypes API works when requesting for a specific chip.
*/
@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();
+ public void testGetSupportedIfaceTypesOneChipTestChipV2() throws Exception {
+ TestChipV2 chipMock = new TestChipV2();
chipMock.initialize();
- mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip);
+ mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
+ mManagerStatusListenerMock);
executeAndValidateInitializationSequence();
- executeAndValidateStartupSequence(1, false);
+ 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 isSupported() returns true when IServiceManager finds the vendor HAL daemon in
- * the VINTF.
- */
- @Test
- public void testIsSupportedTrue() throws Exception {
- mInOrder = inOrder(mServiceManagerMock, mWifiMock);
- executeAndValidateInitializationSequence();
- assertTrue(mDut.isSupported());
- }
-
- /**
- * Validate that isSupported() returns false when IServiceManager does not find the vendor HAL
- * daemon in the VINTF.
- */
- @Test
- public void testIsSupportedFalse() throws Exception {
- when(mServiceManagerMock.getTransport(
- eq(IWifi.kInterfaceName), eq(HalDeviceManager.HAL_INSTANCE_NAME)))
- .thenReturn(IServiceManager.Transport.EMPTY);
- mInOrder = inOrder(mServiceManagerMock, mWifiMock);
- executeAndValidateInitializationSequence(false);
- assertFalse(mDut.isSupported());
- }
-
+ ///////////////////////////////////////////////////////////////////////////////////////
// utilities
+ ///////////////////////////////////////////////////////////////////////////////////////
private void dumpDut(String prefix) {
StringWriter sw = new StringWriter();
mDut.dump(null, new PrintWriter(sw), null);
@@ -1140,7 +1314,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,6 +1330,167 @@
}
}
+ private void runCreateSingleXxxInterfaceNoInitMode(ChipMockBase chipMock, int ifaceTypeToCreate,
+ String ifaceName, int finalChipMode, int expectedAvailableCalls) throws Exception {
+ chipMock.initialize();
+ mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
+ mManagerStatusListenerMock);
+ executeAndValidateInitializationSequence();
+ executeAndValidateStartupSequence();
+
+ HalDeviceManager.InterfaceDestroyedListener idl = mock(
+ HalDeviceManager.InterfaceDestroyedListener.class);
+ HalDeviceManager.InterfaceAvailableForRequestListener iafrl = mock(
+ HalDeviceManager.InterfaceAvailableForRequestListener.class);
+
+ IWifiIface iface = validateInterfaceSequence(chipMock,
+ false, // chipModeValid
+ -1000, // chipModeId (only used if chipModeValid is true)
+ ifaceTypeToCreate,
+ ifaceName,
+ finalChipMode,
+ null, // tearDownList
+ idl, // destroyedListener
+ iafrl // availableListener
+ );
+ collector.checkThat("allocated interface", iface, IsNull.notNullValue());
+
+ // act: remove interface
+ mDut.removeIface(iface);
+ mTestLooper.dispatchAll();
+
+ // verify: callback triggered
+ switch (ifaceTypeToCreate) {
+ case IfaceType.STA:
+ mInOrder.verify(chipMock.chip).removeStaIface(ifaceName);
+ break;
+ case IfaceType.AP:
+ mInOrder.verify(chipMock.chip).removeApIface(ifaceName);
+ break;
+ case IfaceType.P2P:
+ mInOrder.verify(chipMock.chip).removeP2pIface(ifaceName);
+ break;
+ case IfaceType.NAN:
+ mInOrder.verify(chipMock.chip).removeNanIface(ifaceName);
+ break;
+ }
+
+ verify(idl).onDestroyed();
+ verify(iafrl, times(expectedAvailableCalls)).onAvailableForRequest();
+
+ verifyNoMoreInteractions(mManagerStatusListenerMock, idl, iafrl);
+ }
+
+ /**
+ * Validate P2P and NAN interactions. Expect:
+ * - STA created
+ * - NAN created
+ * - When P2P requested:
+ * - NAN torn down
+ * - P2P created
+ * - NAN creation refused
+ * - When P2P destroyed:
+ * - get nan available listener
+ * - Can create NAN when requested
+ *
+ * Relevant for any chip which supports STA + NAN || P2P (or a richer combination - but bottom
+ * line of NAN and P2P being exclusive).
+ */
+ public void runP2pAndNanExclusiveInteractionsTestChip(ChipMockBase chipMock,
+ boolean duplicateStas, int onlyChipMode) throws Exception {
+ chipMock.initialize();
+ mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
+ mManagerStatusListenerMock);
+ executeAndValidateInitializationSequence();
+ executeAndValidateStartupSequence();
+
+ 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
+ onlyChipMode, // finalChipMode
+ null, // tearDownList
+ staDestroyedListener, // destroyedListener
+ staAvailListener // availableListener
+ );
+
+ // Request NAN
+ IWifiIface nanIface = validateInterfaceSequence(chipMock,
+ true, // chipModeValid
+ onlyChipMode, // chipModeId
+ IfaceType.NAN, // ifaceTypeToCreate
+ "nan0", // ifaceName
+ onlyChipMode, // finalChipMode
+ null, // tearDownList
+ nanDestroyedListener, // destroyedListener
+ nanAvailListener // availableListener
+ );
+
+ // Request P2P
+ IWifiIface p2pIface = validateInterfaceSequence(chipMock,
+ true, // chipModeValid
+ onlyChipMode, // chipModeId
+ IfaceType.P2P, // ifaceTypeToCreate
+ "p2p0", // ifaceName
+ onlyChipMode, // finalChipMode
+ new IWifiIface[]{nanIface}, // tearDownList
+ p2pDestroyedListener, // destroyedListener
+ p2pAvailListener, // availableListener
+ nanDestroyedListener // destroyedInterfacesDestroyedListeners...
+ );
+
+ // 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();
+ verify(nanAvailListener).onAvailableForRequest();
+
+ // Request NAN: expect success now
+ nanIface = validateInterfaceSequence(chipMock,
+ true, // chipModeValid
+ onlyChipMode, // chipModeId
+ IfaceType.NAN, // ifaceTypeToCreate
+ "nan0", // ifaceName
+ onlyChipMode, // finalChipMode
+ null, // tearDownList
+ nanDestroyedListener, // destroyedListener
+ nanAvailListener // availableListener
+ );
+
+ if (duplicateStas) {
+ // if there are duplicate STAs then expect an available callback for each step above
+ verify(staAvailListener, times(5)).onAvailableForRequest();
+ }
+
+ verifyNoMoreInteractions(mManagerStatusListenerMock, staDestroyedListener, staAvailListener,
+ nanDestroyedListener, nanAvailListener, p2pDestroyedListener);
+ }
+
private IWifiIface validateInterfaceSequence(ChipMockBase chipMock,
boolean chipModeValid, int chipModeId,
int ifaceTypeToCreate, String ifaceName, int finalChipMode, IWifiIface[] tearDownList,
@@ -1181,7 +1516,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 +1527,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 +1538,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 +1549,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
@@ -1598,10 +1933,10 @@
}
}
- // emulate baseline/legacy config:
- // mode: STA + NAN || P2P
- // mode: NAN
- private class BaselineChip extends ChipMockBase {
+ // test chip configuration V1:
+ // mode: STA + (NAN || P2P)
+ // mode: AP
+ private class TestChipV1 extends ChipMockBase {
static final int STA_CHIP_MODE_ID = 0;
static final int AP_CHIP_MODE_ID = 1;
@@ -1659,4 +1994,60 @@
.getAvailableModes(any(IWifiChip.getAvailableModesCallback.class));
}
}
+
+ // test chip configuration V2:
+ // mode: STA + (STA || AP) + (NAN || P2P)
+ private class TestChipV2 extends ChipMockBase {
+ // only mode (different number from any in TestChipV1 so can catch test errors)
+ static final int CHIP_MODE_ID = 5;
+
+ void initialize() throws Exception {
+ super.initialize();
+
+ // chip Id configuration
+ ArrayList<Integer> chipIds;
+ chipId = 12;
+ chipIds = new ArrayList<>();
+ chipIds.add(chipId);
+ doAnswer(new GetChipIdsAnswer(mStatusOk, chipIds)).when(mWifiMock).getChipIds(
+ any(IWifi.getChipIdsCallback.class));
+
+ doAnswer(new GetChipAnswer(mStatusOk, chip)).when(mWifiMock).getChip(eq(12),
+ any(IWifi.getChipCallback.class));
+
+ // initialize dummy chip modes
+ IWifiChip.ChipMode cm;
+ IWifiChip.ChipIfaceCombination cic;
+ IWifiChip.ChipIfaceCombinationLimit cicl;
+
+ // Mode 0 (only one): 1xSTA + 1x{STA,AP} + 1x{P2P,NAN}
+ availableModes = new ArrayList<>();
+ cm = new IWifiChip.ChipMode();
+ cm.id = CHIP_MODE_ID;
+
+ cic = new IWifiChip.ChipIfaceCombination();
+
+ cicl = new IWifiChip.ChipIfaceCombinationLimit();
+ cicl.maxIfaces = 1;
+ cicl.types.add(IfaceType.STA);
+ cic.limits.add(cicl);
+
+ cicl = new IWifiChip.ChipIfaceCombinationLimit();
+ cicl.maxIfaces = 1;
+ cicl.types.add(IfaceType.STA);
+ cicl.types.add(IfaceType.AP);
+ cic.limits.add(cicl);
+
+ cicl = new IWifiChip.ChipIfaceCombinationLimit();
+ cicl.maxIfaces = 1;
+ cicl.types.add(IfaceType.P2P);
+ cicl.types.add(IfaceType.NAN);
+ cic.limits.add(cicl);
+ cm.availableCombinations.add(cic);
+ availableModes.add(cm);
+
+ doAnswer(new GetAvailableModesAnswer(this)).when(chip)
+ .getAvailableModes(any(IWifiChip.getAvailableModesCallback.class));
+ }
+ }
}
diff --git a/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java b/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java
index 892b597..91234e9 100644
--- a/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java
@@ -16,15 +16,24 @@
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.WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE;
+import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_FAILURE_REASON;
+import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
+import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
+import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE;
+import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
+import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING;
+import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
+import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING;
+import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED;
+import static com.android.server.wifi.LocalOnlyHotspotRequestInfo.HOTSPOT_NO_ERROR;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.*;
+
+import android.content.Context;
+import android.content.Intent;
import android.net.InterfaceConfiguration;
import android.net.wifi.IApInterface;
import android.net.wifi.WifiConfiguration;
@@ -32,6 +41,7 @@
import android.os.IBinder;
import android.os.IBinder.DeathRecipient;
import android.os.INetworkManagementService;
+import android.os.UserHandle;
import android.os.test.TestLooper;
import android.test.suitebuilder.annotation.SmallTest;
@@ -47,6 +57,7 @@
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}. */
@@ -66,6 +77,7 @@
private final WifiConfiguration mDefaultApConfig = createDefaultApConfig();
+ @Mock Context mContext;
TestLooper mLooper;
@Mock WifiNative mWifiNative;
@Mock SoftApManager.Listener mListener;
@@ -102,18 +114,20 @@
return defaultConfig;
}
- private SoftApManager createSoftApManager(WifiConfiguration config) throws Exception {
+ private SoftApManager createSoftApManager(SoftApModeConfiguration config) throws Exception {
when(mApInterface.asBinder()).thenReturn(mApInterfaceBinder);
when(mApInterface.startHostapd()).thenReturn(true);
when(mApInterface.stopHostapd()).thenReturn(true);
- if (config == null) {
+ if (config.getWifiConfiguration() == null) {
when(mWifiApConfigStore.getApConfiguration()).thenReturn(mDefaultApConfig);
}
- SoftApManager newSoftApManager = new SoftApManager(mLooper.getLooper(),
+ SoftApManager newSoftApManager = new SoftApManager(mContext,
+ mLooper.getLooper(),
mWifiNative,
TEST_COUNTRY_CODE,
mListener,
mApInterface,
+ TEST_INTERFACE_NAME,
mNmService,
mWifiApConfigStore,
config,
@@ -125,7 +139,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,7 +150,9 @@
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);
}
@@ -148,7 +166,9 @@
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);
}
/** Tests softap startup if default config fails to load. **/
@@ -158,36 +178,155 @@
when(mApInterface.startHostapd()).thenReturn(true);
when(mApInterface.stopHostapd()).thenReturn(true);
when(mWifiApConfigStore.getApConfiguration()).thenReturn(null);
- SoftApManager newSoftApManager = new SoftApManager(mLooper.getLooper(),
+ SoftApModeConfiguration nullApConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null);
+ SoftApManager newSoftApManager = new SoftApManager(mContext,
+ mLooper.getLooper(),
mWifiNative,
TEST_COUNTRY_CODE,
mListener,
mApInterface,
+ TEST_INTERFACE_NAME,
mNmService,
mWifiApConfigStore,
- null,
+ nullApConfig,
mWifiMetrics);
mLooper.dispatchAll();
newSoftApManager.start();
mLooper.dispatchAll();
verify(mListener).onStateChanged(WifiManager.WIFI_AP_STATE_FAILED,
WifiManager.SAP_START_FAILURE_GENERAL);
+ ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mContext, times(2)).sendStickyBroadcastAsUser(intentCaptor.capture(),
+ eq(UserHandle.ALL));
+
+ List<Intent> capturedIntents = intentCaptor.getAllValues();
+ checkApStateChangedBroadcast(capturedIntents.get(0), WIFI_AP_STATE_ENABLING,
+ WIFI_AP_STATE_DISABLED, HOTSPOT_NO_ERROR, TEST_INTERFACE_NAME,
+ nullApConfig.getTargetMode());
+ checkApStateChangedBroadcast(capturedIntents.get(1), WIFI_AP_STATE_FAILED,
+ WIFI_AP_STATE_ENABLING, WifiManager.SAP_START_FAILURE_GENERAL, TEST_INTERFACE_NAME,
+ nullApConfig.getTargetMode());
}
- /** Tests the handling of stop command when soft AP is not started. */
+ /**
+ * 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(mApInterface.asBinder()).thenReturn(mApInterfaceBinder);
+ when(mApInterface.startHostapd()).thenReturn(true);
+ when(mApInterface.stopHostapd()).thenReturn(true);
+ when(mWifiNative.isHalStarted()).thenReturn(true);
+
+ SoftApManager newSoftApManager = new SoftApManager(mContext,
+ mLooper.getLooper(),
+ mWifiNative,
+ null,
+ mListener,
+ mApInterface,
+ TEST_INTERFACE_NAME,
+ mNmService,
+ mWifiApConfigStore,
+ softApConfig,
+ mWifiMetrics);
+ mLooper.dispatchAll();
+ newSoftApManager.start();
+ mLooper.dispatchAll();
+
+ ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mContext, times(2)).sendStickyBroadcastAsUser(intentCaptor.capture(),
+ eq(UserHandle.ALL));
+
+ List<Intent> capturedIntents = intentCaptor.getAllValues();
+ checkApStateChangedBroadcast(capturedIntents.get(0), WIFI_AP_STATE_ENABLING,
+ WIFI_AP_STATE_DISABLED, HOTSPOT_NO_ERROR, TEST_INTERFACE_NAME,
+ softApConfig.getTargetMode());
+ checkApStateChangedBroadcast(capturedIntents.get(1), WIFI_AP_STATE_FAILED,
+ WIFI_AP_STATE_ENABLING, WifiManager.SAP_START_FAILURE_GENERAL, TEST_INTERFACE_NAME,
+ softApConfig.getTargetMode());
+ }
+
+ /**
+ * Tests that the NO_CHANNEL error is propagated and properly reported when starting softap and
+ * a valid channel cannot be determined.
+ */
+ @Test
+ public void startSoftApFailNoChannel() throws Exception {
+ WifiConfiguration config = new WifiConfiguration();
+ config.apBand = -2;
+ config.apChannel = 0;
+ config.SSID = TEST_SSID;
+ SoftApModeConfiguration softApConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config);
+
+ when(mApInterface.asBinder()).thenReturn(mApInterfaceBinder);
+ when(mApInterface.startHostapd()).thenReturn(true);
+ when(mApInterface.stopHostapd()).thenReturn(true);
+ when(mWifiNative.isHalStarted()).thenReturn(true);
+ when(mWifiNative.isGetChannelsForBandSupported()).thenReturn(true);
+
+ SoftApManager newSoftApManager = new SoftApManager(mContext,
+ mLooper.getLooper(),
+ mWifiNative,
+ TEST_COUNTRY_CODE,
+ mListener,
+ mApInterface,
+ TEST_INTERFACE_NAME,
+ mNmService,
+ mWifiApConfigStore,
+ softApConfig,
+ mWifiMetrics);
+ mLooper.dispatchAll();
+ newSoftApManager.start();
+ mLooper.dispatchAll();
+
+ ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mContext, times(2)).sendStickyBroadcastAsUser(intentCaptor.capture(),
+ eq(UserHandle.ALL));
+
+ List<Intent> capturedIntents = intentCaptor.getAllValues();
+ checkApStateChangedBroadcast(capturedIntents.get(0), WIFI_AP_STATE_ENABLING,
+ WIFI_AP_STATE_DISABLED, HOTSPOT_NO_ERROR, TEST_INTERFACE_NAME,
+ softApConfig.getTargetMode());
+ checkApStateChangedBroadcast(capturedIntents.get(1), WIFI_AP_STATE_FAILED,
+ WIFI_AP_STATE_ENABLING, WifiManager.SAP_START_FAILURE_NO_CHANNEL,
+ TEST_INTERFACE_NAME, softApConfig.getTargetMode());
+ }
+
+
+ /**
+ * Tests 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);
@@ -197,11 +336,30 @@
verify(mApInterface).stopHostapd();
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);
+
+ // reset to clear verified Intents for ap state change updates
+ reset(mContext);
mDeathListenerCaptor.getValue().binderDied();
mLooper.dispatchAll();
@@ -209,10 +367,22 @@
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());
}
/** Starts soft AP and verifies that it is enabled successfully. */
- protected void startSoftApAndVerifyEnabled(WifiConfiguration config) throws Exception {
+ protected void startSoftApAndVerifyEnabled(
+ SoftApModeConfiguration softApConfig) throws Exception {
String expectedSSID;
boolean expectedHiddenSsid;
InOrder order = inOrder(mListener, mApInterfaceBinder, mApInterface, mNmService);
@@ -221,7 +391,8 @@
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;
@@ -231,6 +402,8 @@
expectedHiddenSsid = config.hiddenSSID;
}
+ ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+
mSoftApManager.start();
mLooper.dispatchAll();
order.verify(mListener).onStateChanged(WifiManager.WIFI_AP_STATE_ENABLING, 0);
@@ -243,6 +416,15 @@
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());
}
/** Verifies that soft AP was not disabled. */
@@ -250,4 +432,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/VelocityBasedConnectedScoreTest.java b/tests/wifitests/src/com/android/server/wifi/VelocityBasedConnectedScoreTest.java
new file mode 100644
index 0000000..263cbed
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/VelocityBasedConnectedScoreTest.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wifi;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.net.wifi.WifiInfo;
+
+import com.android.internal.R;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
+
+/**
+ * Unit tests for {@link com.android.server.wifi.VelocityBasedConnectedScore}.
+ */
+public class VelocityBasedConnectedScoreTest {
+
+ private static final int CELLULAR_THRESHOLD_SCORE = 50;
+
+ class FakeClock extends Clock {
+ long mWallClockMillis = 1500000000000L;
+ int mStepMillis = 3001;
+
+ @Override
+ public long getWallClockMillis() {
+ mWallClockMillis += mStepMillis;
+ return mWallClockMillis;
+ }
+ }
+
+ FakeClock mClock;
+ VelocityBasedConnectedScore mVelocityBasedConnectedScore;
+ ScanDetailCache mScanDetailCache;
+ WifiInfo mWifiInfo;
+ int mRssiExitThreshold2GHz;
+ int mRssiExitThreshold5GHz;
+ @Mock Context mContext;
+ @Spy private MockResources mResources = new MockResources();
+
+ private int setupIntegerResource(int resourceName, int value) {
+ doReturn(value).when(mResources).getInteger(resourceName);
+ return value;
+ }
+
+ /**
+ * Sets up resource values for testing
+ *
+ * See frameworks/base/core/res/res/values/config.xml
+ */
+ private void setUpResources(Resources resources) {
+ mRssiExitThreshold2GHz = setupIntegerResource(
+ R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz, -83);
+ mRssiExitThreshold5GHz = setupIntegerResource(
+ R.integer.config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz, -80);
+ }
+
+ /**
+ * Sets up for unit test
+ */
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ setUpResources(mResources);
+ mWifiInfo = new WifiInfo();
+ mWifiInfo.setFrequency(2412);
+ when(mContext.getResources()).thenReturn(mResources);
+ mClock = new FakeClock();
+ mVelocityBasedConnectedScore = new VelocityBasedConnectedScore(mContext, mClock);
+ }
+
+ /**
+ *
+ * Low RSSI, but some data is moving and error rate is low.
+ *
+ * Expect a score above threshold.
+ */
+ @Test
+ public void allowLowRssiIfErrorRateIsLowAndSomeDataIsMoving() throws Exception {
+ mWifiInfo.setRssi(mRssiExitThreshold2GHz - 2);
+ mWifiInfo.setLinkSpeed(6); // Mbps
+ mWifiInfo.txSuccessRate = 10.1; // proportional to pps
+ mWifiInfo.txBadRate = .5;
+ mWifiInfo.rxSuccessRate = 10.1;
+ for (int i = 0; i < 10; i++) {
+ mVelocityBasedConnectedScore.updateUsingWifiInfo(mWifiInfo,
+ mClock.getWallClockMillis());
+ }
+ int score = mVelocityBasedConnectedScore.generateScore();
+ assertTrue(score > CELLULAR_THRESHOLD_SCORE);
+ }
+
+ /**
+ *
+ * Low RSSI, and almost no data is moving.
+ *
+ * Expect a score below threshold.
+ */
+ @Test
+ public void disallowLowRssiIfDataIsNotMoving() throws Exception {
+ mWifiInfo.setRssi(mRssiExitThreshold2GHz - 1);
+ mWifiInfo.setLinkSpeed(6); // Mbps
+ mWifiInfo.txSuccessRate = .1; // proportional to pps
+ mWifiInfo.txBadRate = 0;
+ mWifiInfo.rxSuccessRate = .1;
+ for (int i = 0; i < 10; i++) {
+ mVelocityBasedConnectedScore.updateUsingWifiInfo(mWifiInfo,
+ mClock.getWallClockMillis());
+ }
+ int score = mVelocityBasedConnectedScore.generateScore();
+ assertTrue(score < CELLULAR_THRESHOLD_SCORE);
+ }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java b/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java
index 6e0b775..c6a06e8 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java
@@ -782,6 +782,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 +1085,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 +1133,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 +1167,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 +1189,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 +1209,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 +1404,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/WifiStateMachinePrimeTest.java b/tests/wifitests/src/com/android/server/wifi/WifiStateMachinePrimeTest.java
index 060919d..2e26769 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiStateMachinePrimeTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiStateMachinePrimeTest.java
@@ -92,7 +92,8 @@
}
private void enterSoftApActiveMode() throws Exception {
- enterSoftApActiveMode(null);
+ enterSoftApActiveMode(
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null));
}
/**
@@ -100,10 +101,11 @@
*
* This method puts the test object into the correct state and verifies steps along the way.
*/
- private void enterSoftApActiveMode(WifiConfiguration wifiConfig) throws Exception {
+ private void enterSoftApActiveMode(SoftApModeConfiguration softApConfig) throws Exception {
String fromState = mWifiStateMachinePrime.getCurrentMode();
when(mWifiInjector.makeWificond()).thenReturn(mWificond);
when(mWificond.createApInterface(WIFI_IFACE_NAME)).thenReturn(mApInterface);
+ when(mApInterface.getInterfaceName()).thenReturn(WIFI_IFACE_NAME);
doAnswer(
new Answer<Object>() {
public SoftApManager answer(InvocationOnMock invocation) {
@@ -111,14 +113,16 @@
assertEquals(mNMService, (INetworkManagementService) args[0]);
mSoftApListener = (SoftApManager.Listener) args[1];
assertEquals(mApInterface, (IApInterface) args[2]);
- assertEquals(wifiConfig, (WifiConfiguration) args[3]);
+ assertEquals(WIFI_IFACE_NAME, (String) args[3]);
+ assertEquals(softApConfig, (SoftApModeConfiguration) args[4]);
return mSoftApManager;
}
}).when(mWifiInjector).makeSoftApManager(any(INetworkManagementService.class),
any(SoftApManager.Listener.class),
any(IApInterface.class),
+ anyString(),
any());
- mWifiStateMachinePrime.enterSoftAPMode(wifiConfig);
+ mWifiStateMachinePrime.enterSoftAPMode(softApConfig);
mLooper.dispatchAll();
Log.e("WifiStateMachinePrimeTest", "check fromState: " + fromState);
if (!fromState.equals(WIFI_DISABLED_STATE_STRING)) {
@@ -186,7 +190,8 @@
public void testDisableWifiFromSoftApModeState() throws Exception {
// Use a failure getting wificond to stay in the SoftAPModeState
when(mWifiInjector.makeWificond()).thenReturn(null);
- mWifiStateMachinePrime.enterSoftAPMode(null);
+ mWifiStateMachinePrime.enterSoftAPMode(
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null));
mLooper.dispatchAll();
assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
@@ -221,7 +226,8 @@
@Test
public void testWificondNullWhenSwitchingToApMode() throws Exception {
when(mWifiInjector.makeWificond()).thenReturn(null);
- mWifiStateMachinePrime.enterSoftAPMode(null);
+ mWifiStateMachinePrime.enterSoftAPMode(
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null));
mLooper.dispatchAll();
assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
}
@@ -236,13 +242,14 @@
public void testAPInterfaceFailedWhenSwitchingToApMode() throws Exception {
when(mWifiInjector.makeWificond()).thenReturn(mWificond);
when(mWificond.createApInterface(WIFI_IFACE_NAME)).thenReturn(null);
- mWifiStateMachinePrime.enterSoftAPMode(null);
+ mWifiStateMachinePrime.enterSoftAPMode(
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null));
mLooper.dispatchAll();
assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
}
/**
- * 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.
*/
@@ -250,7 +257,8 @@
public void testEnterSoftApModeActiveWhenAlreadyInSoftApMode() throws Exception {
when(mWifiInjector.makeWificond()).thenReturn(mWificond);
when(mWificond.createApInterface(WIFI_IFACE_NAME)).thenReturn(null);
- mWifiStateMachinePrime.enterSoftAPMode(null);
+ mWifiStateMachinePrime.enterSoftAPMode(
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null));
mLooper.dispatchAll();
assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
@@ -297,7 +305,9 @@
public void testConfigIsPassedToWifiInjector() throws Exception {
WifiConfiguration config = new WifiConfiguration();
config.SSID = "ThisIsAConfig";
- enterSoftApActiveMode(config);
+ SoftApModeConfiguration softApConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config);
+ enterSoftApActiveMode(softApConfig);
}
/**
@@ -310,7 +320,7 @@
*/
@Test
public void testNullConfigIsPassedToWifiInjector() throws Exception {
- enterSoftApActiveMode(null);
+ enterSoftApActiveMode();
}
/**
@@ -319,22 +329,25 @@
* config - this second call should use the correct config.
*/
@Test
- public void testNullConfigFailsSecondCallWithConfigSuccessful() throws Exception {
+ public void testNullApModeConfigFails() throws Exception {
when(mWifiInjector.makeWificond()).thenReturn(mWificond);
when(mWificond.createApInterface(WIFI_IFACE_NAME)).thenReturn(null);
- mWifiStateMachinePrime.enterSoftAPMode(null);
+ mWifiStateMachinePrime.enterSoftAPMode(
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null));
mLooper.dispatchAll();
assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
WifiConfiguration config = new WifiConfiguration();
config.SSID = "ThisIsAConfig";
- enterSoftApActiveMode(config);
+ SoftApModeConfiguration softApConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config);
+ enterSoftApActiveMode(softApConfig);
}
/**
- * Test that a failed call to start softap with a valid config has the config saved for future
- * calls to enable softap.
+ * Test that a failed call to start softap with a valid config does not persist the ap
+ * configuration to the WifiApConfigStore.
*
- * Expectations: A call to start SoftAPMode with a config should write out the config if we
+ * Expectations: A call to start SoftAPMode with a config should not write out the config if we
* did not create a SoftApManager.
*/
@Test
@@ -343,10 +356,12 @@
when(mWifiInjector.getWifiApConfigStore()).thenReturn(mWifiApConfigStore);
WifiConfiguration config = new WifiConfiguration();
config.SSID = "ThisIsAConfig";
- mWifiStateMachinePrime.enterSoftAPMode(config);
+ SoftApModeConfiguration softApConfig =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config);
+ mWifiStateMachinePrime.enterSoftAPMode(softApConfig);
mLooper.dispatchAll();
assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
- verify(mWifiApConfigStore).setApConfiguration(eq(config));
+ verify(mWifiApConfigStore, never()).setApConfiguration(eq(config));
}
/**
@@ -358,26 +373,33 @@
public void testStartSoftApModeTwiceWithTwoConfigs() throws Exception {
when(mWifiInjector.makeWificond()).thenReturn(mWificond);
when(mWificond.createApInterface(WIFI_IFACE_NAME)).thenReturn(mApInterface);
+ when(mApInterface.getInterfaceName()).thenReturn(WIFI_IFACE_NAME);
when(mWifiInjector.getWifiApConfigStore()).thenReturn(mWifiApConfigStore);
WifiConfiguration config1 = new WifiConfiguration();
config1.SSID = "ThisIsAConfig";
+ SoftApModeConfiguration softApConfig1 =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config1);
WifiConfiguration config2 = new WifiConfiguration();
config2.SSID = "ThisIsASecondConfig";
+ SoftApModeConfiguration softApConfig2 =
+ new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config2);
when(mWifiInjector.makeSoftApManager(any(INetworkManagementService.class),
any(SoftApManager.Listener.class),
any(IApInterface.class),
- eq(config1)))
+ anyString(),
+ eq(softApConfig1)))
.thenReturn(mSoftApManager);
when(mWifiInjector.makeSoftApManager(any(INetworkManagementService.class),
any(SoftApManager.Listener.class),
any(IApInterface.class),
- eq(config2)))
+ anyString(),
+ eq(softApConfig2)))
.thenReturn(mSoftApManager);
- mWifiStateMachinePrime.enterSoftAPMode(config1);
- mWifiStateMachinePrime.enterSoftAPMode(config2);
+ mWifiStateMachinePrime.enterSoftAPMode(softApConfig1);
+ mWifiStateMachinePrime.enterSoftAPMode(softApConfig2);
mLooper.dispatchAll();
assertEquals(SOFT_AP_MODE_ACTIVE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java b/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
index f7c98ea..51beee9 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiStateMachineTest.java
@@ -51,7 +51,7 @@
import android.net.NetworkFactory;
import android.net.NetworkRequest;
import android.net.dhcp.DhcpClient;
-import android.net.ip.IpManager;
+import android.net.ip.IpClient;
import android.net.wifi.IApInterface;
import android.net.wifi.IClientInterface;
import android.net.wifi.IWificond;
@@ -199,12 +199,12 @@
IBinder batteryStatsBinder = mockService(BatteryStats.class, IBatteryStats.class);
when(facade.getService(BatteryStats.SERVICE_NAME)).thenReturn(batteryStatsBinder);
- when(facade.makeIpManager(any(Context.class), anyString(), any(IpManager.Callback.class)))
+ when(facade.makeIpClient(any(Context.class), anyString(), any(IpClient.Callback.class)))
.then(new AnswerWithArguments() {
- public IpManager answer(
- Context context, String ifname, IpManager.Callback callback) {
- mIpManagerCallback = callback;
- return mIpManager;
+ public IpClient answer(
+ Context context, String ifname, IpClient.Callback callback) {
+ mIpClientCallback = callback;
+ return mIpClient;
}
});
@@ -302,13 +302,13 @@
}
private void injectDhcpSuccess(DhcpResults dhcpResults) {
- mIpManagerCallback.onNewDhcpResults(dhcpResults);
- mIpManagerCallback.onProvisioningSuccess(new LinkProperties());
+ mIpClientCallback.onNewDhcpResults(dhcpResults);
+ mIpClientCallback.onProvisioningSuccess(new LinkProperties());
}
private void injectDhcpFailure() {
- mIpManagerCallback.onNewDhcpResults(null);
- mIpManagerCallback.onProvisioningFailure(new LinkProperties());
+ mIpClientCallback.onNewDhcpResults(null);
+ mIpClientCallback.onProvisioningFailure(new LinkProperties());
}
static final String sSSID = "\"GoogleGuest\"";
@@ -331,7 +331,7 @@
Context mContext;
MockResources mResources;
FrameworkFacade mFrameworkFacade;
- IpManager.Callback mIpManagerCallback;
+ IpClient.Callback mIpClientCallback;
PhoneStateListener mPhoneStateListener;
NetworkRequest mDefaultNetworkRequest;
@@ -363,7 +363,7 @@
@Mock PasspointManager mPasspointManager;
@Mock SelfRecovery mSelfRecovery;
@Mock WifiPermissionsUtil mWifiPermissionsUtil;
- @Mock IpManager mIpManager;
+ @Mock IpClient mIpClient;
@Mock TelephonyManager mTelephonyManager;
@Mock WrongPasswordNotifier mWrongPasswordNotifier;
@Mock Clock mClock;
@@ -401,8 +401,9 @@
when(mWifiInjector.makeWifiConnectivityManager(any(WifiInfo.class), anyBoolean()))
.thenReturn(mWifiConnectivityManager);
when(mWifiInjector.makeSoftApManager(any(INetworkManagementService.class),
- mSoftApManagerListenerCaptor.capture(), any(IApInterface.class),
- any(WifiConfiguration.class)))
+ mSoftApManagerListenerCaptor.capture(),
+ any(IApInterface.class), anyString(),
+ any(SoftApModeConfiguration.class)))
.thenReturn(mSoftApManager);
when(mWifiInjector.getPasspointManager()).thenReturn(mPasspointManager);
when(mWifiInjector.getWifiStateTracker()).thenReturn(mWifiStateTracker);
@@ -588,30 +589,17 @@
verify(mWifiNative).setupForSoftApMode(WIFI_IFACE_NAME);
verify(mSoftApManager).start();
- // reset expectations for mContext due to previously sent AP broadcast
- reset(mContext);
-
// get the SoftApManager.Listener and trigger some updates
SoftApManager.Listener listener = mSoftApManagerListenerCaptor.getValue();
listener.onStateChanged(WIFI_AP_STATE_ENABLING, 0);
+ assertEquals(WIFI_AP_STATE_ENABLING, mWsm.syncGetWifiApState());
listener.onStateChanged(WIFI_AP_STATE_ENABLED, 0);
+ assertEquals(WIFI_AP_STATE_ENABLED, mWsm.syncGetWifiApState());
listener.onStateChanged(WIFI_AP_STATE_DISABLING, 0);
+ assertEquals(WIFI_AP_STATE_DISABLING, mWsm.syncGetWifiApState());
// note, this will trigger a mode change when TestLooper is dispatched
listener.onStateChanged(WIFI_AP_STATE_DISABLED, 0);
-
- 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);
+ assertEquals(WIFI_AP_STATE_DISABLED, mWsm.syncGetWifiApState());
}
@Test
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiVendorHalTest.java b/tests/wifitests/src/com/android/server/wifi/WifiVendorHalTest.java
index f6524e0..362d3b1 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;
@@ -58,6 +82,7 @@
import android.net.wifi.WifiScanner;
import android.net.wifi.WifiSsid;
import android.net.wifi.WifiWakeReasonAndCounts;
+import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
import android.os.test.TestLooper;
@@ -66,9 +91,6 @@
import com.android.server.connectivity.KeepalivePacketData;
import com.android.server.wifi.util.NativeUtil;
-import static org.junit.Assert.*;
-import static org.mockito.Mockito.*;
-
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
@@ -203,7 +225,8 @@
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();
}
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..e5a7968 100644
--- a/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareNativeManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareNativeManagerTest.java
@@ -28,6 +28,7 @@
import android.hardware.wifi.V1_0.IfaceType;
import android.hardware.wifi.V1_0.WifiStatus;
import android.hardware.wifi.V1_0.WifiStatusCode;
+import android.os.Handler;
import com.android.server.wifi.HalDeviceManager;
@@ -49,6 +50,7 @@
@Mock private HalDeviceManager mHalDeviceManager;
@Mock private WifiAwareNativeCallback mWifiAwareNativeCallback;
@Mock private IWifiNanIface mWifiNanIfaceMock;
+ @Mock private Handler mHandlerMock;
private ArgumentCaptor<HalDeviceManager.ManagerStatusListener> mManagerStatusListenerCaptor =
ArgumentCaptor.forClass(HalDeviceManager.ManagerStatusListener.class);
private ArgumentCaptor<HalDeviceManager.InterfaceDestroyedListener>
@@ -73,7 +75,7 @@
mDut = new WifiAwareNativeManager(mWifiAwareStateManagerMock,
mHalDeviceManager, mWifiAwareNativeCallback);
- mDut.start();
+ mDut.start(mHandlerMock);
mInOrder = inOrder(mWifiAwareStateManagerMock, mHalDeviceManager);
}
@@ -106,7 +108,7 @@
mManagerStatusListenerCaptor.getValue().onStatusChanged();
mInOrder.verify(mHalDeviceManager).registerInterfaceAvailableForRequestListener(
- eq(IfaceType.NAN), mAvailListenerCaptor.capture(), any());
+ eq(IfaceType.NAN), mAvailListenerCaptor.capture(), any(Handler.class));
mAvailListenerCaptor.getValue().onAvailableForRequest();
mInOrder.verify(mHalDeviceManager).createNanIface(
@@ -137,7 +139,7 @@
mManagerStatusListenerCaptor.getValue().onStatusChanged();
mInOrder.verify(mHalDeviceManager).registerInterfaceAvailableForRequestListener(
- eq(IfaceType.NAN), mAvailListenerCaptor.capture(), any());
+ eq(IfaceType.NAN), mAvailListenerCaptor.capture(), any(Handler.class));
mAvailListenerCaptor.getValue().onAvailableForRequest();
mInOrder.verify(mHalDeviceManager).createNanIface(
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 ec4c4ba..a391d3d 100644
--- a/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareStateManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/aware/WifiAwareStateManagerTest.java
@@ -3060,7 +3060,7 @@
ArgumentCaptor<Short> transactionId = ArgumentCaptor.forClass(Short.class);
IWifiAwareEventCallback mockCallback = mock(IWifiAwareEventCallback.class);
InOrder inOrder = inOrder(mMockContext, mMockNativeManager, mMockNative, mockCallback);
- inOrder.verify(mMockNativeManager).start();
+ inOrder.verify(mMockNativeManager).start(any(Handler.class));
mDut.enableUsage();
mMockLooper.dispatchAll();
diff --git a/tests/wifitests/src/com/android/server/wifi/rtt/RttNativeTest.java b/tests/wifitests/src/com/android/server/wifi/rtt/RttNativeTest.java
index a1b22e0..51fed83 100644
--- a/tests/wifitests/src/com/android/server/wifi/rtt/RttNativeTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/rtt/RttNativeTest.java
@@ -18,6 +18,8 @@
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;
@@ -90,6 +92,8 @@
mDut.start();
verify(mockHalDeviceManager).registerStatusListener(mHdmStatusListener.capture(), any());
verify(mockRttController).registerEventCallback(any());
+ verify(mockRttServiceImpl).enable();
+ assertTrue(mDut.isReady());
}
/**
@@ -144,11 +148,13 @@
// (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(mockRttController);
+ verifyNoMoreInteractions(mockRttServiceImpl, 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
index 410d4d9..bfeb068 100644
--- a/tests/wifitests/src/com/android/server/wifi/rtt/RttServiceImplTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/rtt/RttServiceImplTest.java
@@ -21,14 +21,17 @@
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -37,7 +40,10 @@
import android.app.AlarmManager;
import android.app.test.MockAnswerUtil;
import android.app.test.TestAlarmManager;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.hardware.wifi.V1_0.RttResult;
import android.net.wifi.aware.IWifiAwareMacAddressProvider;
import android.net.wifi.aware.IWifiAwareManager;
@@ -46,9 +52,13 @@
import android.net.wifi.rtt.RangingRequest;
import android.net.wifi.rtt.RangingResult;
import android.net.wifi.rtt.RangingResultCallback;
+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.test.TestLooper;
import android.util.Pair;
@@ -75,6 +85,8 @@
private RttServiceImplSpy mDut;
private TestLooper mMockLooper;
private TestAlarmManager mAlarmManager;
+ private PowerManager mMockPowerManager;
+ private BroadcastReceiver mPowerBcastReceiver;
private final String mPackageName = "some.package.name.for.rtt.app";
private int mDefaultUid = 1500;
@@ -138,13 +150,29 @@
mAlarmManager = new TestAlarmManager();
when(mockContext.getSystemService(Context.ALARM_SERVICE))
.thenReturn(mAlarmManager.getAlarmManager());
- mInOrder = inOrder(mAlarmManager.getAlarmManager());
+ mInOrder = inOrder(mAlarmManager.getAlarmManager(), mockContext);
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);
+
mDut.start(mMockLooper.getLooper(), mockAwareManagerBinder, mockNative, mockPermissionUtil);
+ mMockLooper.dispatchAll();
+ ArgumentCaptor<BroadcastReceiver> bcastRxCaptor = ArgumentCaptor.forClass(
+ BroadcastReceiver.class);
+ verify(mockContext).registerReceiver(bcastRxCaptor.capture(), any(IntentFilter.class));
+ verify(mockNative).start();
+ mPowerBcastReceiver = bcastRxCaptor.getValue();
+
+ assertTrue(mDut.isAvailable());
}
/**
@@ -185,6 +213,7 @@
mMockLooper.dispatchAll();
}
+ verify(mockNative, atLeastOnce()).isReady();
verifyNoMoreInteractions(mockNative, mockCallback, mAlarmManager.getAlarmManager());
}
@@ -232,6 +261,7 @@
assertTrue(compareListContentsNoOrdering(results.second, mListCaptor.getValue()));
+ verify(mockNative, atLeastOnce()).isReady();
verifyNoMoreInteractions(mockNative, mockCallback, mAlarmManager.getAlarmManager());
}
@@ -282,6 +312,7 @@
}
}
+ verify(mockNative, atLeastOnce()).isReady();
verifyNoMoreInteractions(mockNative, mockCallback, mAlarmManager.getAlarmManager());
}
@@ -312,6 +343,7 @@
verify(mockCallback).onRangingFailure(eq(RangingResultCallback.STATUS_CODE_FAIL));
verifyWakeupCancelled();
+ verify(mockNative, atLeastOnce()).isReady();
verifyNoMoreInteractions(mockNative, mockCallback, mAlarmManager.getAlarmManager());
}
@@ -379,6 +411,7 @@
}
}
+ verify(mockNative, atLeastOnce()).isReady();
verifyNoMoreInteractions(mockNative, mockCallback, mAlarmManager.getAlarmManager());
}
@@ -413,6 +446,7 @@
verify(mockCallback).onRangingResults(results.second);
verifyWakeupCancelled();
+ verify(mockNative, atLeastOnce()).isReady();
verifyNoMoreInteractions(mockNative, mockCallback, mAlarmManager.getAlarmManager());
}
@@ -447,6 +481,7 @@
assertTrue(compareListContentsNoOrdering(results.second, mListCaptor.getValue()));
verifyWakeupCancelled();
+ verify(mockNative, atLeastOnce()).isReady();
verifyNoMoreInteractions(mockNative, mockCallback, mAlarmManager.getAlarmManager());
}
@@ -492,13 +527,103 @@
verify(mockCallback).onRangingResults(result2.second);
verifyWakeupCancelled();
+ verify(mockNative, atLeastOnce()).isReady();
verifyNoMoreInteractions(mockNative, mockCallback, mAlarmManager.getAlarmManager());
}
+ /**
+ * Validate that when Wi-Fi gets disabled (HAL level) the ranging queue gets cleared.
+ */
+ @Test
+ public void testDisableWifiFlow() throws Exception {
+ runDisableRttFlow(true);
+ }
+
+ /**
+ * Validate that when Doze mode starts, RTT gets disabled and the ranging queue gets cleared.
+ */
+ @Test
+ public void testDozeModeFlow() throws Exception {
+ runDisableRttFlow(false);
+ }
+
+ /**
+ * Actually execute the disable RTT flow: either by disabling Wi-Fi or enabling doze.
+ *
+ * @param disableWifi true to disable Wi-Fi, false to enable doze
+ */
+ private void runDisableRttFlow(boolean disableWifi) throws Exception {
+ RangingRequest request1 = RttTestUtils.getDummyRangingRequest((byte) 1);
+ RangingRequest request2 = RttTestUtils.getDummyRangingRequest((byte) 2);
+ RangingRequest request3 = RttTestUtils.getDummyRangingRequest((byte) 3);
+
+ IRttCallback mockCallback2 = mock(IRttCallback.class);
+ IRttCallback mockCallback3 = mock(IRttCallback.class);
+
+ // (1) request 2 ranging operations: request 1 should be sent to HAL
+ mDut.startRanging(mockIbinder, mPackageName, request1, mockCallback);
+ mDut.startRanging(mockIbinder, mPackageName, request2, mockCallback2);
+ mMockLooper.dispatchAll();
+
+ verify(mockNative).rangeRequest(mIntCaptor.capture(), eq(request1));
+ verifyWakeupSet();
+
+ // (2) disable RTT: all requests should "fail"
+ if (disableWifi) {
+ when(mockNative.isReady()).thenReturn(false);
+ mDut.disable();
+ } else {
+ simulatePowerStateChangeDoze(true);
+ }
+ mMockLooper.dispatchAll();
+
+ assertFalse(mDut.isAvailable());
+ validateCorrectRttStatusChangeBroadcast(false);
+ verify(mockNative).rangeCancel(eq(mIntCaptor.getValue()), any());
+ verify(mockCallback).onRangingFailure(
+ RangingResultCallback.STATUS_CODE_FAIL_RTT_NOT_AVAILABLE);
+ verify(mockCallback2).onRangingFailure(
+ RangingResultCallback.STATUS_CODE_FAIL_RTT_NOT_AVAILABLE);
+ verifyWakeupCancelled();
+
+ // (3) issue another request: it should fail
+ mDut.startRanging(mockIbinder, mPackageName, request3, mockCallback3);
+ mMockLooper.dispatchAll();
+
+ verify(mockCallback3).onRangingFailure(
+ RangingResultCallback.STATUS_CODE_FAIL_RTT_NOT_AVAILABLE);
+
+ // (4) enable RTT: nothing should happen (no requests in queue!)
+ if (disableWifi) {
+ when(mockNative.isReady()).thenReturn(true);
+ mDut.enable();
+ } else {
+ simulatePowerStateChangeDoze(false);
+ }
+ mMockLooper.dispatchAll();
+
+ assertTrue(mDut.isAvailable());
+ validateCorrectRttStatusChangeBroadcast(true);
+ verify(mockNative, atLeastOnce()).isReady();
+ verifyNoMoreInteractions(mockNative, mockCallback, mockCallback2, mockCallback3,
+ mAlarmManager.getAlarmManager());
+ }
+
/*
* Utilities
*/
+ /**
+ * Simulate power state change due to doze. Changes the power manager return values and
+ * dispatches a broadcast.
+ */
+ private void simulatePowerStateChangeDoze(boolean isDozeOn) {
+ when(mMockPowerManager.isDeviceIdleMode()).thenReturn(isDozeOn);
+
+ Intent intent = new Intent(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
+ mPowerBcastReceiver.onReceive(mockContext, intent);
+ }
+
private void verifyWakeupSet() {
mInOrder.verify(mAlarmManager.getAlarmManager()).setExact(anyInt(), anyLong(),
eq(RttServiceImpl.HAL_RANGING_TIMEOUT_TAG), any(AlarmManager.OnAlarmListener.class),
@@ -510,6 +635,19 @@
any(AlarmManager.OnAlarmListener.class));
}
+ /**
+ * Validates that the broadcast sent on RTT status change is correct.
+ *
+ * @param expectedEnabled The expected change status - i.e. are we expected to announce that
+ * RTT is enabled (true) or disabled (false).
+ */
+ private void validateCorrectRttStatusChangeBroadcast(boolean expectedEnabled) {
+ ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);
+
+ mInOrder.verify(mockContext).sendBroadcastAsUser(intent.capture(), eq(UserHandle.ALL));
+ assertEquals(intent.getValue().getAction(), WifiRttManager.ACTION_WIFI_RTT_STATE_CHANGED);
+ }
+
private class AwareTranslatePeerHandlesToMac extends MockAnswerUtil.AnswerWithArguments {
private int mExpectedUid;
private Map<Integer, byte[]> mPeerIdToMacMap;