[HDM] New chip configuration: priority updates & tests
Add support and test code for chip configuration:
- STA + (STA || AP)
- STA + (NAN || P2P)
Update priorities to specify that any but 1st interface (e.g.
second STA, second AP) have the lowest priority and can be
removed for any other interface.
Bug: 69863101
Test: unit test
Change-Id: Id98907b192da8a6a13c8f837942f6e0b76981058
diff --git a/service/java/com/android/server/wifi/HalDeviceManager.java b/service/java/com/android/server/wifi/HalDeviceManager.java
index ffc7113..d65f31f 100644
--- a/service/java/com/android/server/wifi/HalDeviceManager.java
+++ b/service/java/com/android/server/wifi/HalDeviceManager.java
@@ -1485,7 +1485,7 @@
for (int type: IFACE_TYPES_BY_PRIORITY) {
if (chipInfo.ifaces[type].length != 0) {
if (!allowedToDeleteIfaceTypeForRequestedType(type, ifaceType,
- chipInfo.ifaces[ifaceType].length != 0)) {
+ chipInfo.ifaces)) {
if (DBG) {
Log.d(TAG, "Couldn't delete existing type " + type
+ " interfaces for requested type");
@@ -1515,8 +1515,7 @@
}
if (tooManyInterfaces > 0) { // may need to delete some
- if (!allowedToDeleteIfaceTypeForRequestedType(type, ifaceType,
- chipInfo.ifaces[ifaceType].length != 0)) {
+ if (!allowedToDeleteIfaceTypeForRequestedType(type, ifaceType, chipInfo.ifaces)) {
if (DBG) {
Log.d(TAG, "Would need to delete some higher priority interfaces");
}
@@ -1592,37 +1591,48 @@
* Returns true if we're allowed to delete the existing interface type for the requested
* interface type.
*
- * Rules:
- * 1. Request for AP or STA will destroy any other interface (except see #4 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
+ * Rules - applies in order:
+ *
+ * General rules:
+ * 1. No interface will be destroyed for a requested interface of the same type
+ * 2. No interface will be destroyed if one of the requested interfaces already exists
+ * 3. If there are >1 interface of an existing type, then it is ok to destroy that type
+ * interface
+ *
+ * Type-specific rules (but note that the general rules are appied first):
+ * 4. Request for AP or STA will destroy any other interface
+ * 5. Request for P2P will destroy NAN-only (but will destroy a second STA per #3)
+ * 6. Request for NAN will not destroy any interface (but will destroy a second STA per #3)
+
*/
private boolean allowedToDeleteIfaceTypeForRequestedType(int existingIfaceType,
- int requestedIfaceType, boolean requestedIfaceTypeAlreadyExists) {
- // rule 5
- if (requestedIfaceTypeAlreadyExists) {
- return false;
- }
-
- // rule 4
+ int requestedIfaceType, WifiIfaceInfo[][] currentIfaces) {
+ // rule 1
if (existingIfaceType == requestedIfaceType) {
return false;
}
+ // rule 2
+ if (currentIfaces[requestedIfaceType].length != 0) {
+ return false;
+ }
+
// rule 3
+ if (currentIfaces[existingIfaceType].length > 1) {
+ return true;
+ }
+
+ // rule 6
if (requestedIfaceType == IfaceType.NAN) {
return false;
}
- // rule 2
+ // rule 5
if (requestedIfaceType == IfaceType.P2P) {
return existingIfaceType == IfaceType.NAN;
}
- // rule 1, the requestIfaceType is either AP or STA
+ // rule 4, the requestIfaceType is either AP or STA
return true;
}
diff --git a/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java b/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java
index 18a1f8f..4290ada 100644
--- a/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java
@@ -17,7 +17,6 @@
package com.android.server.wifi;
import static com.android.server.wifi.HalDeviceManager.START_HAL_RETRY_TIMES;
-import static com.android.server.wifi.HalDeviceManager.getName;
import static junit.framework.Assert.assertEquals;
@@ -589,6 +588,48 @@
TestChipV2.CHIP_MODE_ID, 1);
}
+ // TestChipV3
+
+ /**
+ * Validate creation of STA interface from blank start-up. The remove interface.
+ */
+ @Test
+ public void testCreateStaInterfaceNoInitModeTestChipV3() throws Exception {
+ // Note: we expected 2 available callbacks since we now have 2 STAs possible. So
+ // we get callback 1 after creating the first STA (since we can create another STA),
+ // and we get callback 2 after destroying the first STA (since we can create another STA -
+ // as expected).
+ runCreateSingleXxxInterfaceNoInitMode(new TestChipV3(), IfaceType.STA, "sta0",
+ TestChipV3.CHIP_MODE_ID, 2);
+ }
+
+ /**
+ * Validate creation of AP interface from blank start-up. The remove interface.
+ */
+ @Test
+ public void testCreateApInterfaceNoInitModeTestChipV3() throws Exception {
+ runCreateSingleXxxInterfaceNoInitMode(new TestChipV3(), IfaceType.AP, "ap0",
+ TestChipV3.CHIP_MODE_ID, 1);
+ }
+
+ /**
+ * Validate creation of P2P interface from blank start-up. The remove interface.
+ */
+ @Test
+ public void testCreateP2pInterfaceNoInitModeTestChipV3() throws Exception {
+ runCreateSingleXxxInterfaceNoInitMode(new TestChipV3(), IfaceType.P2P, "p2p0",
+ TestChipV3.CHIP_MODE_ID, 1);
+ }
+
+ /**
+ * Validate creation of NAN interface from blank start-up. The remove interface.
+ */
+ @Test
+ public void testCreateNanInterfaceNoInitModeTestChipV3() throws Exception {
+ runCreateSingleXxxInterfaceNoInitMode(new TestChipV3(), IfaceType.NAN, "nan0",
+ TestChipV3.CHIP_MODE_ID, 1);
+ }
+
//////////////////////////////////////////////////////////////////////////////////////
// TestChipV1 Specific Tests
//////////////////////////////////////////////////////////////////////////////////////
@@ -982,8 +1023,9 @@
*/
@Test
public void testP2pAndNanInteractionsTestChipV1() throws Exception {
- runP2pAndNanExclusiveInteractionsTestChip(new TestChipV1(), false,
- TestChipV1.STA_CHIP_MODE_ID);
+ // staAvailCallbacks=0: there is no second STA so will never get available callback after
+ // first is created.
+ runP2pAndNanExclusiveInteractionsTestChip(new TestChipV1(), 0, TestChipV1.STA_CHIP_MODE_ID);
}
/**
@@ -1298,7 +1340,9 @@
*/
@Test
public void testP2pAndNanInteractionsTestChipV2() throws Exception {
- runP2pAndNanExclusiveInteractionsTestChip(new TestChipV2(), true, TestChipV2.CHIP_MODE_ID);
+ // staAvailCallbacks=5: after every substantial change will get a callback since second
+ // STA is always available.
+ runP2pAndNanExclusiveInteractionsTestChip(new TestChipV2(), 5, TestChipV2.CHIP_MODE_ID);
}
/**
@@ -1351,6 +1395,273 @@
assertEquals(correctResults, results);
}
+ //////////////////////////////////////////////////////////////////////////////////////
+ // TestChipV3 Specific Tests
+ //////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Validate a flow sequence for test chip 3:
+ * - create STA
+ * - create P2P
+ * - request NAN: failure
+ * - create AP: should tear down P2P first
+ * - create STA: will get refused
+ * - create AP: will get refused
+ * - request P2P: failure
+ * - tear down AP
+ * - create STA
+ * - create STA: will get refused
+ * - create NAN: should tear down last created STA
+ * - create STA: will get refused
+ */
+ @Test
+ public void testInterfaceCreationFlowTestChipV3() throws Exception {
+ TestChipV3 chipMock = new TestChipV3();
+ chipMock.initialize();
+ mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
+ mManagerStatusListenerMock);
+ executeAndValidateInitializationSequence();
+ executeAndValidateStartupSequence();
+
+ InterfaceDestroyedListener staDestroyedListener = mock(
+ InterfaceDestroyedListener.class);
+ InterfaceDestroyedListener staDestroyedListener2 = mock(
+ InterfaceDestroyedListener.class);
+ HalDeviceManager.InterfaceAvailableForRequestListener staAvailListener = mock(
+ HalDeviceManager.InterfaceAvailableForRequestListener.class);
+
+ InterfaceDestroyedListener apDestroyedListener = mock(
+ InterfaceDestroyedListener.class);
+ HalDeviceManager.InterfaceAvailableForRequestListener apAvailListener = mock(
+ HalDeviceManager.InterfaceAvailableForRequestListener.class);
+
+ InterfaceDestroyedListener p2pDestroyedListener = mock(
+ InterfaceDestroyedListener.class);
+ HalDeviceManager.InterfaceAvailableForRequestListener p2pAvailListener = mock(
+ HalDeviceManager.InterfaceAvailableForRequestListener.class);
+
+ InterfaceDestroyedListener nanDestroyedListener = mock(
+ InterfaceDestroyedListener.class);
+ HalDeviceManager.InterfaceAvailableForRequestListener nanAvailListener = mock(
+ HalDeviceManager.InterfaceAvailableForRequestListener.class);
+
+ InOrder 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
+ TestChipV3.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
+ TestChipV3.CHIP_MODE_ID, // chipModeId
+ IfaceType.P2P, // ifaceTypeToCreate
+ "p2p0", // ifaceName
+ TestChipV3.CHIP_MODE_ID, // finalChipMode
+ null, // tearDownList
+ p2pDestroyedListener, // destroyedListener
+ null // availableListener (already registered)
+ );
+ collector.checkThat("P2P interface wasn't created", p2pIface, IsNull.notNullValue());
+
+ 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: will destroy P2P
+ IWifiIface apIface = validateInterfaceSequence(chipMock,
+ true, // chipModeValid
+ TestChipV3.CHIP_MODE_ID, // chipModeId
+ IfaceType.AP, // ifaceTypeToCreate
+ "ap0", // ifaceName
+ TestChipV3.CHIP_MODE_ID, // finalChipMode
+ null, // tearDownList
+ apDestroyedListener, // destroyedListener
+ null, // availableListener (already registered)
+ new InterfaceDestroyedListenerWithIfaceName("p2p0", p2pDestroyedListener)
+ );
+ collector.checkThat("AP interface wasn't created", apIface, IsNull.notNullValue());
+ verify(chipMock.chip).removeP2pIface("p2p0");
+
+ // request STA2: should fail
+ IWifiIface staIface2 = mDut.createStaIface(null, null);
+ collector.checkThat("STA2 should not be created", staIface2, IsNull.nullValue());
+
+ // request AP2: should fail
+ IWifiIface apIface2 = mDut.createApIface(null, null);
+ collector.checkThat("AP2 should not be created", apIface2, IsNull.nullValue());
+
+ // request P2P: should fail
+ p2pIface = mDut.createP2pIface(null, null);
+ collector.checkThat("P2P should not be created", p2pIface, IsNull.nullValue());
+
+ // tear down AP
+ mDut.removeIface(apIface);
+ mTestLooper.dispatchAll();
+
+ inOrderStaAvail.verify(staAvailListener).onAvailableForRequest();
+ inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
+ inOrderP2pAvail.verify(p2pAvailListener).onAvailableForRequest();
+ inOrderNanAvail.verify(nanAvailListener).onAvailableForRequest();
+ verify(chipMock.chip).removeApIface("ap0");
+ verify(apDestroyedListener).onDestroyed(getName(apIface));
+
+ // create STA2: using a later clock
+ when(mClock.getUptimeSinceBootMillis()).thenReturn(20L);
+ staIface2 = validateInterfaceSequence(chipMock,
+ true, // chipModeValid
+ TestChipV3.CHIP_MODE_ID, // chipModeId
+ IfaceType.STA, // ifaceTypeToCreate
+ "sta1", // ifaceName
+ TestChipV3.CHIP_MODE_ID, // finalChipMode
+ null, // tearDownList
+ staDestroyedListener2, // destroyedListener
+ null // availableListener (already registered)
+ );
+ collector.checkThat("STA 2 interface wasn't created", staIface2, IsNull.notNullValue());
+
+ inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
+ inOrderP2pAvail.verify(p2pAvailListener).onAvailableForRequest();
+ inOrderNanAvail.verify(nanAvailListener).onAvailableForRequest();
+
+ // request STA3: should fail
+ IWifiIface staIface3 = mDut.createStaIface(null, null);
+ collector.checkThat("STA3 should not be created", staIface3, IsNull.nullValue());
+
+ // create NAN: should destroy the last created STA (STA2)
+ nanIface = validateInterfaceSequence(chipMock,
+ true, // chipModeValid
+ TestChipV3.CHIP_MODE_ID, // chipModeId
+ IfaceType.NAN, // ifaceTypeToCreate
+ "nan0", // ifaceName
+ TestChipV3.CHIP_MODE_ID, // finalChipMode
+ null, // tearDownList
+ nanDestroyedListener, // destroyedListener
+ null, // availableListener (already registered)
+ new InterfaceDestroyedListenerWithIfaceName(
+ getName(staIface2), staDestroyedListener2)
+ );
+ collector.checkThat("NAN interface wasn't created", nanIface, IsNull.notNullValue());
+
+ inOrderApAvail.verify(apAvailListener).onAvailableForRequest();
+ inOrderP2pAvail.verify(p2pAvailListener).onAvailableForRequest();
+ verify(chipMock.chip).removeStaIface("sta1");
+ verify(staDestroyedListener2).onDestroyed(getName(staIface2));
+
+ // request STA2: should fail
+ staIface2 = mDut.createStaIface(null, null);
+ collector.checkThat("STA2 should not be created", staIface2, IsNull.nullValue());
+
+ verifyNoMoreInteractions(mManagerStatusListenerMock, staDestroyedListener,
+ staDestroyedListener2, apDestroyedListener, p2pDestroyedListener,
+ nanDestroyedListener, staAvailListener, apAvailListener, p2pAvailListener,
+ nanAvailListener, staAvailListener, apAvailListener, p2pAvailListener,
+ nanAvailListener);
+ }
+
+ /**
+ * Validate P2P and NAN interactions. Expect:
+ * - STA created
+ * - NAN created
+ * - When P2P requested:
+ * - NAN torn down
+ * - P2P created
+ * - NAN creation refused
+ * - When P2P destroyed:
+ * - get nan available listener
+ * - Can create NAN when requested
+ */
+ @Test
+ public void testP2pAndNanInteractionsTestChipV3() throws Exception {
+ // staAvailCallbacks=2: only get callback (for second STA) when P2P or NAN are down.
+ runP2pAndNanExclusiveInteractionsTestChip(new TestChipV3(), 2, TestChipV3.CHIP_MODE_ID);
+ }
+
+ /**
+ * Validate that the getSupportedIfaceTypes API works when requesting for all chips.
+ */
+ @Test
+ public void testGetSupportedIfaceTypesAllTestChipV3() throws Exception {
+ TestChipV3 chipMock = new TestChipV3();
+ chipMock.initialize();
+ mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
+ mManagerStatusListenerMock);
+ executeAndValidateInitializationSequence();
+ executeAndValidateStartupSequence();
+
+ // try API
+ Set<Integer> results = mDut.getSupportedIfaceTypes();
+
+ // verify results
+ Set<Integer> correctResults = new HashSet<>();
+ correctResults.add(IfaceType.AP);
+ correctResults.add(IfaceType.STA);
+ correctResults.add(IfaceType.P2P);
+ correctResults.add(IfaceType.NAN);
+
+ assertEquals(correctResults, results);
+ }
+
+ /**
+ * Validate that the getSupportedIfaceTypes API works when requesting for a specific chip.
+ */
+ @Test
+ public void testGetSupportedIfaceTypesOneChipTestChipV3() throws Exception {
+ TestChipV3 chipMock = new TestChipV3();
+ chipMock.initialize();
+ mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
+ mManagerStatusListenerMock);
+ executeAndValidateInitializationSequence();
+ executeAndValidateStartupSequence();
+
+ // try API
+ Set<Integer> results = mDut.getSupportedIfaceTypes(chipMock.chip);
+
+ // verify results
+ Set<Integer> correctResults = new HashSet<>();
+ correctResults.add(IfaceType.AP);
+ correctResults.add(IfaceType.STA);
+ correctResults.add(IfaceType.P2P);
+ correctResults.add(IfaceType.NAN);
+
+ assertEquals(correctResults, results);
+ }
+
///////////////////////////////////////////////////////////////////////////////////////
// utilities
///////////////////////////////////////////////////////////////////////////////////////
@@ -1480,7 +1791,7 @@
* line of NAN and P2P being exclusive).
*/
public void runP2pAndNanExclusiveInteractionsTestChip(ChipMockBase chipMock,
- boolean duplicateStas, int onlyChipMode) throws Exception {
+ int staAvailCallbacks, int onlyChipMode) throws Exception {
chipMock.initialize();
mInOrder = inOrder(mServiceManagerMock, mWifiMock, chipMock.chip,
mManagerStatusListenerMock);
@@ -1567,9 +1878,9 @@
nanAvailListener // availableListener
);
- if (duplicateStas) {
+ if (staAvailCallbacks != 0) {
// if there are duplicate STAs then expect an available callback for each step above
- verify(staAvailListener, times(5)).onAvailableForRequest();
+ verify(staAvailListener, times(staAvailCallbacks)).onAvailableForRequest();
}
verifyNoMoreInteractions(mManagerStatusListenerMock, staDestroyedListener, staAvailListener,
@@ -2149,4 +2460,72 @@
.getAvailableModes(any(IWifiChip.getAvailableModesCallback.class));
}
}
+
+ // test chip configuration V3:
+ // mode:
+ // STA + (STA || AP)
+ // STA + (NAN || P2P)
+ private class TestChipV3 extends ChipMockBase {
+ // only mode (different number from any in other TestChips so can catch test errors)
+ static final int CHIP_MODE_ID = 7;
+
+ void initialize() throws Exception {
+ super.initialize();
+
+ // chip Id configuration
+ ArrayList<Integer> chipIds;
+ chipId = 15;
+ chipIds = new ArrayList<>();
+ chipIds.add(chipId);
+ doAnswer(new GetChipIdsAnswer(mStatusOk, chipIds)).when(mWifiMock).getChipIds(
+ any(IWifi.getChipIdsCallback.class));
+
+ doAnswer(new GetChipAnswer(mStatusOk, chip)).when(mWifiMock).getChip(eq(15),
+ any(IWifi.getChipCallback.class));
+
+ // initialize dummy chip modes
+ IWifiChip.ChipMode cm;
+ IWifiChip.ChipIfaceCombination cic;
+ IWifiChip.ChipIfaceCombinationLimit cicl;
+
+ // Mode 0 (only one): 1xSTA + 1x{STA,AP}, 1xSTA + 1x{P2P,NAN}
+ availableModes = new ArrayList<>();
+ cm = new IWifiChip.ChipMode();
+ cm.id = CHIP_MODE_ID;
+
+ cic = new IWifiChip.ChipIfaceCombination();
+
+ cicl = new IWifiChip.ChipIfaceCombinationLimit();
+ cicl.maxIfaces = 1;
+ cicl.types.add(IfaceType.STA);
+ cic.limits.add(cicl);
+
+ cicl = new IWifiChip.ChipIfaceCombinationLimit();
+ cicl.maxIfaces = 1;
+ cicl.types.add(IfaceType.STA);
+ cicl.types.add(IfaceType.AP);
+ cic.limits.add(cicl);
+
+ cm.availableCombinations.add(cic);
+
+ cic = new IWifiChip.ChipIfaceCombination();
+
+ cicl = new IWifiChip.ChipIfaceCombinationLimit();
+ cicl.maxIfaces = 1;
+ cicl.types.add(IfaceType.STA);
+ cic.limits.add(cicl);
+
+ cicl = new IWifiChip.ChipIfaceCombinationLimit();
+ cicl.maxIfaces = 1;
+ cicl.types.add(IfaceType.P2P);
+ cicl.types.add(IfaceType.NAN);
+ cic.limits.add(cicl);
+
+ cm.availableCombinations.add(cic);
+ availableModes.add(cm);
+
+ doAnswer(new GetAvailableModesAnswer(this)).when(chip)
+ .getAvailableModes(any(IWifiChip.getAvailableModesCallback.class));
+ }
+ }
}