WifiNetworkFactory: Stop caching CMM instance
CMM instance creation / re-use should be controlled centrally by
ActiveModeWarden. Caching CMM instance locally in WifiNetworkFactory (when a new
request comes in while procesing another request) can lead to the device
connecting to the same bssid via 2 CMM.
Bug: 148935691
Test: atest com.android.server.wifi
Change-Id: Ia12ec0c32685b50026b415cd195540c8ec402544
diff --git a/service/java/com/android/server/wifi/ActiveModeWarden.java b/service/java/com/android/server/wifi/ActiveModeWarden.java
index 06243eb..9e8c146 100644
--- a/service/java/com/android/server/wifi/ActiveModeWarden.java
+++ b/service/java/com/android/server/wifi/ActiveModeWarden.java
@@ -1373,6 +1373,22 @@
return true;
}
+ private void handleAdditionalClientModeManagerRequest(
+ @NonNull AdditionalClientModeManagerRequestInfo requestInfo) {
+ ClientModeManager cmm = getClientModeManagerInRole(requestInfo.clientRole);
+ if (cmm != null) {
+ // Already have a client mode manager in the requested role.
+ requestInfo.listener.onAnswer(cmm);
+ } else if (shouldRequestAdditionalClientModeManager(requestInfo)) {
+ // Can create an additional client mode manager.
+ startAdditionalClientModeManager(
+ requestInfo.clientRole,
+ requestInfo.listener, requestInfo.requestorWs);
+ } else {
+ requestInfo.listener.onAnswer(getPrimaryClientModeManager());
+ }
+ }
+
@Override
public boolean processMessageFiltered(Message msg) {
@@ -1391,16 +1407,8 @@
}
break;
case CMD_REQUEST_ADDITIONAL_CLIENT_MODE_MANAGER:
- AdditionalClientModeManagerRequestInfo requestInfo =
- (AdditionalClientModeManagerRequestInfo) msg.obj;
- if (shouldRequestAdditionalClientModeManager(requestInfo)) {
- // Can create an additional client mode manager.
- startAdditionalClientModeManager(
- requestInfo.clientRole,
- requestInfo.listener, requestInfo.requestorWs);
- } else {
- requestInfo.listener.onAnswer(getPrimaryClientModeManager());
- }
+ handleAdditionalClientModeManagerRequest(
+ (AdditionalClientModeManagerRequestInfo) msg.obj);
break;
case CMD_REMOVE_ADDITIONAL_CLIENT_MODE_MANAGER:
stopAdditionalClientModeManager((ClientModeManager) msg.obj);
diff --git a/service/java/com/android/server/wifi/WifiNetworkFactory.java b/service/java/com/android/server/wifi/WifiNetworkFactory.java
index 205a9e0..a3d4019 100644
--- a/service/java/com/android/server/wifi/WifiNetworkFactory.java
+++ b/service/java/com/android/server/wifi/WifiNetworkFactory.java
@@ -161,7 +161,6 @@
private boolean mIsPeriodicScanPaused = false;
// We sent a new connection request and are waiting for connection success.
private boolean mPendingConnectionSuccess = false;
- private boolean mAwaitingClientModeManagerRetrieval = false;
/**
* Indicates that we have new data to serialize.
*/
@@ -335,7 +334,6 @@
ActiveModeWarden.ExternalClientModeManagerRequestListener {
@Override
public void onAnswer(@Nullable ClientModeManager modeManager) {
- mAwaitingClientModeManagerRetrieval = false;
if (modeManager != null) {
// Remove the mode manager if the associated request is no longer active.
if (mActiveSpecificNetworkRequest == null
@@ -656,32 +654,6 @@
return true;
}
- private void requestClientModeManagerIfNecessary() {
- // If we already have a ClientModeManager instance retrieved or requested for the
- // previously active request, use that to handle the new request. Creating a new one for
- // overlapping requests would result in unnecessary delay in turning down the old one &
- // creating a new one.
- if (mClientModeManager != null) {
- if (mVerboseLoggingEnabled) Log.v(TAG, "Using cached ClientModeManager instance");
- handleClientModeManagerRetrieval();
- } else if (mAwaitingClientModeManagerRetrieval) {
- // Note: If we have a pending request, then we will wait for the answer to that
- // request to perform the next steps.
- if (mVerboseLoggingEnabled) {
- Log.v(TAG, "Waiting for previously requested ClientModeManager instance");
- }
- } else {
- // No ClientModeManager instance retrieved or requested, request a new instance and
- // then perform the next steps.
- if (mVerboseLoggingEnabled) Log.v(TAG, "Requesting new ClientModeManager instance");
- mAwaitingClientModeManagerRetrieval = true;
- mActiveModeWarden.requestLocalOnlyClientModeManager(
- new ClientModeManagerRequestListener(),
- new WorkSource(mActiveSpecificNetworkRequest.getRequestorUid(),
- mActiveSpecificNetworkRequest.getRequestorPackageName()));
- }
- }
-
/**
* Handle new network connection requests.
*
@@ -930,7 +902,11 @@
mUserSelectedNetwork = networkToConnect;
// Request a new CMM for the connection processing.
- requestClientModeManagerIfNecessary();
+ if (mVerboseLoggingEnabled) Log.v(TAG, "Requesting new ClientModeManager instance");
+ mActiveModeWarden.requestLocalOnlyClientModeManager(
+ new ClientModeManagerRequestListener(),
+ new WorkSource(mActiveSpecificNetworkRequest.getRequestorUid(),
+ mActiveSpecificNetworkRequest.getRequestorPackageName()));
}
private void handleConnectToNetworkUserSelection(WifiConfiguration network) {
diff --git a/service/tests/wifitests/src/com/android/server/wifi/ActiveModeWardenTest.java b/service/tests/wifitests/src/com/android/server/wifi/ActiveModeWardenTest.java
index 4fbe7a5..6241fde 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/ActiveModeWardenTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/ActiveModeWardenTest.java
@@ -2492,6 +2492,69 @@
verify(externalRequestListener).onAnswer(null);
}
+ public void requestAdditionalClientModeManagerWhenAlreadyPresent(
+ ActiveModeManager.ClientConnectivityRole role) throws Exception {
+ enterClientModeActiveState();
+
+ ConcreteClientModeManager additionalClientModeManager =
+ mock(ConcreteClientModeManager.class);
+ Mutable<ActiveModeManager.Listener<ConcreteClientModeManager>> additionalClientListener =
+ new Mutable<>();
+ doAnswer((invocation) -> {
+ Object[] args = invocation.getArguments();
+ additionalClientListener.value =
+ (ActiveModeManager.Listener<ConcreteClientModeManager>) args[0];
+ return additionalClientModeManager;
+ }).when(mWifiInjector).makeClientModeManager(
+ any(ActiveModeManager.Listener.class), any(), eq(role),
+ anyBoolean());
+ when(additionalClientModeManager.getRole()).thenReturn(role);
+
+ ActiveModeWarden.ExternalClientModeManagerRequestListener externalRequestListener = mock(
+ ActiveModeWarden.ExternalClientModeManagerRequestListener.class);
+ if (role == ROLE_CLIENT_LOCAL_ONLY) {
+ mActiveModeWarden.requestLocalOnlyClientModeManager(
+ externalRequestListener, TEST_WORKSOURCE);
+ } else if (role == ROLE_CLIENT_SECONDARY_LONG_LIVED) {
+ mActiveModeWarden.requestSecondaryLongLivedClientModeManager(
+ externalRequestListener, TEST_WORKSOURCE);
+ } else if (role == ROLE_CLIENT_SECONDARY_TRANSIENT) {
+ mActiveModeWarden.requestSecondaryTransientClientModeManager(
+ externalRequestListener, TEST_WORKSOURCE);
+ }
+ mLooper.dispatchAll();
+ verify(mWifiInjector).makeClientModeManager(
+ any(), eq(TEST_WORKSOURCE), eq(role), anyBoolean());
+ additionalClientListener.value.onStarted(additionalClientModeManager);
+ mLooper.dispatchAll();
+ // Returns the new client mode manager.
+ ArgumentCaptor<ClientModeManager> requestedClientModeManager =
+ ArgumentCaptor.forClass(ClientModeManager.class);
+ verify(externalRequestListener).onAnswer(requestedClientModeManager.capture());
+ assertEquals(additionalClientModeManager, requestedClientModeManager.getValue());
+
+ // request for one more CMM (returns the existing one).
+ if (role == ROLE_CLIENT_LOCAL_ONLY) {
+ mActiveModeWarden.requestLocalOnlyClientModeManager(
+ externalRequestListener, TEST_WORKSOURCE);
+ } else if (role == ROLE_CLIENT_SECONDARY_LONG_LIVED) {
+ mActiveModeWarden.requestSecondaryLongLivedClientModeManager(
+ externalRequestListener, TEST_WORKSOURCE);
+ } else if (role == ROLE_CLIENT_SECONDARY_TRANSIENT) {
+ mActiveModeWarden.requestSecondaryTransientClientModeManager(
+ externalRequestListener, TEST_WORKSOURCE);
+ }
+ mLooper.dispatchAll();
+
+ // Don't make another client mode manager.
+ verify(mWifiInjector, times(1))
+ .makeClientModeManager(any(), any(), eq(role), anyBoolean());
+ // Returns the existing client mode manager.
+ verify(externalRequestListener, times(2)).onAnswer(requestedClientModeManager.capture());
+ assertEquals(additionalClientModeManager, requestedClientModeManager.getValue());
+
+ }
+
@Test
public void requestRemoveLocalOnlyClientModeManager() throws Exception {
// Ensure that we can create more client ifaces.
@@ -2531,6 +2594,17 @@
}
@Test
+ public void requestLocalOnlyClientModeManagerWhenAlreadyPresent() throws Exception {
+ // Ensure that we can create more client ifaces.
+ when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
+ assertTrue(mActiveModeWarden.canRequestMoreClientModeManagers(any()));
+ when(mResources.getBoolean(R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled))
+ .thenReturn(true);
+
+ requestAdditionalClientModeManagerWhenAlreadyPresent(ROLE_CLIENT_LOCAL_ONLY);
+ }
+
+ @Test
public void requestRemoveSecondaryLongLivedClientModeManager() throws Exception {
// Ensure that we can create more client ifaces.
when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
@@ -2558,6 +2632,17 @@
}
@Test
+ public void requestSecondaryLongLivedClientModeManagerWhenAlreadyPresent() throws Exception {
+ // Ensure that we can create more client ifaces.
+ when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
+ assertTrue(mActiveModeWarden.canRequestMoreClientModeManagers(any()));
+ when(mResources.getBoolean(R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled))
+ .thenReturn(true);
+
+ requestAdditionalClientModeManagerWhenAlreadyPresent(ROLE_CLIENT_SECONDARY_LONG_LIVED);
+ }
+
+ @Test
public void requestRemoveSecondaryTransientClientModeManager() throws Exception {
// Ensure that we can create more client ifaces.
when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
@@ -2585,6 +2670,17 @@
}
@Test
+ public void requestSecondaryTransientClientModeManagerWhenAlreadyPresent() throws Exception {
+ // Ensure that we can create more client ifaces.
+ when(mWifiNative.isItPossibleToCreateStaIface(any())).thenReturn(true);
+ assertTrue(mActiveModeWarden.canRequestMoreClientModeManagers(any()));
+ when(mResources.getBoolean(R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled))
+ .thenReturn(true);
+
+ requestAdditionalClientModeManagerWhenAlreadyPresent(ROLE_CLIENT_SECONDARY_TRANSIENT);
+ }
+
+ @Test
public void airplaneModeToggleOnDisablesWifi() throws Exception {
enterClientModeActiveState();
assertInEnabledState();
diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiNetworkFactoryTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiNetworkFactoryTest.java
index 428126f..d32cc46 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/WifiNetworkFactoryTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/WifiNetworkFactoryTest.java
@@ -1774,44 +1774,6 @@
* Verify handling of request release after starting connection to the network.
*/
@Test
- public void testHandleNetworkReleaseWithSpecifierWhenAwaitingCmRetrieval() throws Exception {
- doNothing().when(mActiveModeWarden).requestLocalOnlyClientModeManager(any(), any());
-
- when(mClock.getElapsedSinceBootMillis()).thenReturn(0L);
-
- sendNetworkRequestAndSetupForUserSelection();
-
- INetworkRequestUserSelectionCallback networkRequestUserSelectionCallback =
- mNetworkRequestUserSelectionCallback.getValue();
- assertNotNull(networkRequestUserSelectionCallback);
-
- // Now trigger user selection to one of the network.
- mSelectedNetwork = WifiConfigurationTestUtil.createPskNetwork();
- mSelectedNetwork.SSID = "\"" + TEST_SSID_1 + "\"";
- sendUserSelectionSelect(networkRequestUserSelectionCallback, mSelectedNetwork);
- mLooper.dispatchAll();
-
- ArgumentCaptor<ActiveModeWarden.ExternalClientModeManagerRequestListener> cmListenerCaptor =
- ArgumentCaptor.forClass(
- ActiveModeWarden.ExternalClientModeManagerRequestListener.class);
- verify(mActiveModeWarden).requestLocalOnlyClientModeManager(
- cmListenerCaptor.capture(), eq(new WorkSource(TEST_UID_1, TEST_PACKAGE_NAME_1)));
- assertNotNull(cmListenerCaptor.getValue());
-
- // Release the request before the CM instance is delivered.
- mWifiNetworkFactory.releaseNetworkFor(mNetworkRequest);
-
- // Now return the CM instance for the previous request.
- cmListenerCaptor.getValue().onAnswer(mClientModeManager);
-
- // Ensure we removed the CM instance since we no longer have any active request.
- verify(mActiveModeWarden).removeClientModeManager(mClientModeManager);
- }
-
- /**
- * Verify handling of request release after starting connection to the network.
- */
- @Test
public void testHandleNetworkReleaseWithSpecifierAfterConnectionStart() throws Exception {
sendNetworkRequestAndSetupForConnectionStatus();
@@ -1959,8 +1921,8 @@
sendUserSelectionSelect(networkRequestUserSelectionCallback, mSelectedNetwork);
mLooper.dispatchAll();
- // Ensure we don't request a new ClientModeManager.
- verify(mActiveModeWarden, times(1)).requestLocalOnlyClientModeManager(any(), any());
+ // Ensure we request a new ClientModeManager.
+ verify(mActiveModeWarden, times(2)).requestLocalOnlyClientModeManager(any(), any());
// Now return the CM instance for the previous request.
cmListenerCaptor.getValue().onAnswer(mClientModeManager);
@@ -2873,7 +2835,7 @@
sendUserSelectionSelect(networkRequestUserSelectionCallback, mSelectedNetwork);
mLooper.dispatchAll();
- verify(mActiveModeWarden).requestLocalOnlyClientModeManager(any(), any());
+ verify(mActiveModeWarden, atLeastOnce()).requestLocalOnlyClientModeManager(any(), any());
// Cancel the periodic scan timer.
mInOrder.verify(mAlarmManager).cancel(mPeriodicScanListenerArgumentCaptor.getValue());