WifiConnectivityManager: stop caching ClientModeManagers

Instead, get it from ActiveModeWarden directly,
so that they don't accidentally go out of sync.

Also, call onActiveModeManagerRemoved callbacks
when a mode manager fails to start (onStartFailure).
If a failure occurs while switching roles, the
mode manager would have already been added, so
need to notify listeners of the removal.

Bug: 169772923
Test: atest FrameworksWifiTests
Test: toggle wifi a few times
Change-Id: I67c07f6cb3ab69d92302b7aaa623357c59486bbf
diff --git a/service/java/com/android/server/wifi/ActiveModeWarden.java b/service/java/com/android/server/wifi/ActiveModeWarden.java
index ec42313..89cbc24 100644
--- a/service/java/com/android/server/wifi/ActiveModeWarden.java
+++ b/service/java/com/android/server/wifi/ActiveModeWarden.java
@@ -243,18 +243,27 @@
     }
 
     private void invokeOnAddedCallbacks(@NonNull ActiveModeManager activeModeManager) {
+        if (mVerboseLoggingEnabled) {
+            Log.v(TAG, "ModeManager added " + activeModeManager);
+        }
         for (ModeChangeCallback callback : mCallbacks) {
             callback.onActiveModeManagerAdded(activeModeManager);
         }
     }
 
     private void invokeOnRemovedCallbacks(@NonNull ActiveModeManager activeModeManager) {
+        if (mVerboseLoggingEnabled) {
+            Log.v(TAG, "ModeManager removed " + activeModeManager);
+        }
         for (ModeChangeCallback callback : mCallbacks) {
             callback.onActiveModeManagerRemoved(activeModeManager);
         }
     }
 
     private void invokeOnRoleChangedCallbacks(@NonNull ActiveModeManager activeModeManager) {
+        if (mVerboseLoggingEnabled) {
+            Log.v(TAG, "ModeManager role changed " + activeModeManager);
+        }
         for (ModeChangeCallback callback : mCallbacks) {
             callback.onActiveModeManagerRoleChanged(activeModeManager);
         }
@@ -880,6 +889,10 @@
             mGraveyard.inter(softApManager);
             updateBatteryStats();
             mWifiController.sendMessage(WifiController.CMD_AP_START_FAILURE);
+            // onStartFailure can be called when switching between roles. So, remove
+            // update listeners.
+            Log.e(TAG, "SoftApManager start failed!" + softApManager);
+            invokeOnRemovedCallbacks(softApManager);
         }
     }
 
@@ -930,6 +943,10 @@
             updateClientScanMode();
             updateBatteryStats();
             mWifiController.sendMessage(WifiController.CMD_STA_START_FAILURE);
+            // onStartFailure can be called when switching between roles. So, remove
+            // update listeners.
+            Log.e(TAG, "ClientModeManager start failed!" + clientModeManager);
+            invokeOnRemovedCallbacks(clientModeManager);
         }
     }
 
diff --git a/service/java/com/android/server/wifi/ConcreteClientModeManager.java b/service/java/com/android/server/wifi/ConcreteClientModeManager.java
index 21f0177..213ce06 100644
--- a/service/java/com/android/server/wifi/ConcreteClientModeManager.java
+++ b/service/java/com/android/server/wifi/ConcreteClientModeManager.java
@@ -1128,6 +1128,9 @@
 
     @Override
     public String toString() {
-        return "ClientModeManager[" + mClientInterfaceName + "](" + mRole + ":" + mId + ")";
+        return "ConcreteClientModeManager{id=" + getId()
+                + " iface=" + getInterfaceName()
+                + " role=" + getRole()
+                + "}";
     }
 }
diff --git a/service/java/com/android/server/wifi/DefaultClientModeManager.java b/service/java/com/android/server/wifi/DefaultClientModeManager.java
index 4fd0ecf..c3e210e 100644
--- a/service/java/com/android/server/wifi/DefaultClientModeManager.java
+++ b/service/java/com/android/server/wifi/DefaultClientModeManager.java
@@ -64,6 +64,9 @@
 
     @Override
     public String toString() {
-        return "ClientModeManager(Default)";
+        return "DefaultClientModeManager{id=" + getId()
+                + " iface=" + getInterfaceName()
+                + " role=" + getRole()
+                + "}";
     }
 }
diff --git a/service/java/com/android/server/wifi/SoftApManager.java b/service/java/com/android/server/wifi/SoftApManager.java
index 363ec9e..3c0206e 100644
--- a/service/java/com/android/server/wifi/SoftApManager.java
+++ b/service/java/com/android/server/wifi/SoftApManager.java
@@ -329,7 +329,10 @@
 
     @Override
     public String toString() {
-        return "SoftApManager[" + mApInterfaceName + "](" + mRole + ":" + mId + ")";
+        return "SoftApManager{id=" + getId()
+                + " iface=" + getInterfaceName()
+                + " role=" + getRole()
+                + "}";
     }
 
     private String getCurrentStateName() {
diff --git a/service/java/com/android/server/wifi/WifiConnectivityManager.java b/service/java/com/android/server/wifi/WifiConnectivityManager.java
index 4920840..295dbf1 100644
--- a/service/java/com/android/server/wifi/WifiConnectivityManager.java
+++ b/service/java/com/android/server/wifi/WifiConnectivityManager.java
@@ -16,7 +16,6 @@
 
 package com.android.server.wifi;
 
-import static com.android.server.wifi.ActiveModeManager.ClientInternetConnectivityRole;
 import static com.android.server.wifi.ClientModeImpl.WIFI_WORK_SOURCE;
 
 import android.annotation.NonNull;
@@ -42,7 +41,6 @@
 import android.os.Process;
 import android.os.WorkSource;
 import android.util.ArrayMap;
-import android.util.ArraySet;
 import android.util.LocalLog;
 import android.util.Log;
 
@@ -210,10 +208,6 @@
     private @DeviceMobilityState int mDeviceMobilityState =
             WifiManager.DEVICE_MOBILITY_STATE_UNKNOWN;
 
-    // Set of active client mode managers. This would be more than 1 only in case of
-    // STA + STA use-cases.
-    private final ArraySet<ClientModeManager> mClientModeManagers = new ArraySet<>();
-
     // A helper to log debugging information in the local log buffer, which can
     // be retrieved in bugreport.
     private void localLog(String log) {
@@ -780,39 +774,23 @@
     private class ModeChangeCallback implements ActiveModeWarden.ModeChangeCallback {
         @Override
         public void onActiveModeManagerAdded(@NonNull ActiveModeManager activeModeManager) {
-            if (!(activeModeManager instanceof ClientModeManager)) return;
-            if (mVerboseLoggingEnabled) {
-                Log.v(TAG, "ModeManager added " + activeModeManager);
-            }
-            if (activeModeManager.getRole() instanceof ClientInternetConnectivityRole) {
-                mClientModeManagers.add((ClientModeManager) activeModeManager);
-            }
-            setWifiEnabled(!mClientModeManagers.isEmpty());
+            update();
         }
 
         @Override
         public void onActiveModeManagerRemoved(@NonNull ActiveModeManager activeModeManager) {
-            if (!(activeModeManager instanceof ClientModeManager)) return;
-            if (mVerboseLoggingEnabled) {
-                Log.v(TAG, "ModeManager removed " + activeModeManager);
-            }
-            // No need to check for role when mode manager is removed.
-            mClientModeManagers.remove(activeModeManager);
-            setWifiEnabled(!mClientModeManagers.isEmpty());
+            update();
         }
 
         @Override
         public void onActiveModeManagerRoleChanged(@NonNull ActiveModeManager activeModeManager) {
-            if (!(activeModeManager instanceof ClientModeManager)) return;
-            if (mVerboseLoggingEnabled) {
-                Log.v(TAG, "ModeManager role changed " + activeModeManager);
-            }
-            if (activeModeManager.getRole() instanceof ClientInternetConnectivityRole) {
-                mClientModeManagers.add((ClientModeManager) activeModeManager);
-            } else {
-                mClientModeManagers.remove(activeModeManager);
-            }
-            setWifiEnabled(!mClientModeManagers.isEmpty());
+            update();
+        }
+
+        private void update() {
+            List<ClientModeManager> primaryManagers =
+                    mActiveModeWarden.getInternetConnectivityClientModeManagers();
+            setWifiEnabled(!primaryManagers.isEmpty());
         }
     }
 
@@ -893,10 +871,7 @@
 
     private ClientModeManager getPrimaryClientModeManager() {
         // There should only be 1 primary client mode manager at any point of time.
-        return mClientModeManagers.stream()
-                .filter(cm -> cm.getRole() == ActiveModeManager.ROLE_CLIENT_PRIMARY)
-                .findFirst()
-                .get();
+        return mActiveModeWarden.getPrimaryClientModeManager();
     }
 
     /** Initialize single scanning schedules, and validate them */
@@ -1803,9 +1778,11 @@
      * Handler for WiFi state (connected/disconnected) changes
      */
     public void handleConnectionStateChanged(ActiveModeManager activeModeManager, int state) {
-        if (!mClientModeManagers.contains(activeModeManager)) {
-            Log.w(TAG, "Ignoring call from non primary Mode Manager "
-                    + activeModeManager.getRole(), new Throwable());
+        List<ClientModeManager> primaryManagers =
+                mActiveModeWarden.getInternetConnectivityClientModeManagers();
+        if (!(primaryManagers.contains(activeModeManager))) {
+            Log.w(TAG, "Ignoring call from non primary Mode Manager " + activeModeManager,
+                    new Throwable());
             return;
         }
         localLog("handleConnectionStateChanged: state=" + stateToString(state));
@@ -1859,9 +1836,11 @@
      */
     public void handleConnectionAttemptEnded(@NonNull ActiveModeManager activeModeManager,
             int failureCode, @NonNull String bssid, @NonNull String ssid) {
-        if (!mClientModeManagers.contains(activeModeManager)) {
-            Log.w(TAG, "Ignoring call from non primary Mode Manager"
-                    + activeModeManager.getRole(), new Throwable());
+        List<ClientModeManager> primaryManagers =
+                mActiveModeWarden.getInternetConnectivityClientModeManagers();
+        if (!(primaryManagers.contains(activeModeManager))) {
+            Log.w(TAG, "Ignoring call from non primary Mode Manager " + activeModeManager,
+                    new Throwable());
             return;
         }
         if (failureCode == WifiMetrics.ConnectionEvent.FAILURE_NONE) {
@@ -2114,9 +2093,5 @@
         pw.println("WifiConnectivityManager - Log End ----");
         mOpenNetworkNotifier.dump(fd, pw, args);
         mBssidBlocklistMonitor.dump(fd, pw, args);
-        pw.println("mClientModeManager IDs: "
-                + mClientModeManagers.stream()
-                        .map(m -> String.valueOf(m.getId()))
-                        .collect(Collectors.joining(", ")));
     }
 }
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 9e049ec..519edf5 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/ActiveModeWardenTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/ActiveModeWardenTest.java
@@ -692,6 +692,7 @@
         // now inject failure through the SoftApManager.Listener
         mSoftApListener.onStartFailure();
         mLooper.dispatchAll();
+        verify(mModeChangeCallback).onActiveModeManagerRemoved(mSoftApManager);
         assertInDisabledState();
         // clear the first call to start SoftApManager
         reset(mSoftApManager, mBatteryStats, mModeChangeCallback);
@@ -709,6 +710,7 @@
         // now inject a failure through the ScanOnlyModeManager.Listener
         mClientListener.onStartFailure();
         mLooper.dispatchAll();
+        verify(mModeChangeCallback).onActiveModeManagerRemoved(mClientModeManager);
         assertInDisabledState();
         verify(mBatteryStats).reportWifiOff();
     }
@@ -723,6 +725,7 @@
         // now inject failure through the SoftApManager.Listener
         mSoftApListener.onStartFailure();
         mLooper.dispatchAll();
+        verify(mModeChangeCallback).onActiveModeManagerRemoved(mSoftApManager);
         verify(mBatteryStats).reportWifiOff();
     }
 
@@ -752,6 +755,7 @@
         // now inject failure through the SoftApManager.Listener
         mSoftApListener.onStartFailure();
         mLooper.dispatchAll();
+        verify(mModeChangeCallback).onActiveModeManagerRemoved(mSoftApManager);
         verify(mBatteryStats).reportWifiOff();
         verifyNoMoreInteractions(mWifiNative);
     }
diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java
index 4020cf9..8e2eaf1 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java
@@ -127,6 +127,7 @@
         when(mContext.getSystemService(PowerManager.class)).thenReturn(powerManager);
         when(powerManager.isInteractive()).thenReturn(false);
         when(mPrimaryClientModeManager.getRole()).thenReturn(ActiveModeManager.ROLE_CLIENT_PRIMARY);
+        when(mActiveModeWarden.getPrimaryClientModeManager()).thenReturn(mPrimaryClientModeManager);
 
         mWifiConnectivityManager = createConnectivityManager();
         mWifiConnectivityManager.setTrustedConnectionAllowed(true);
@@ -3397,8 +3398,12 @@
                 mModeChangeCallbackCaptor.getValue();
         assertNotNull(modeChangeCallback);
         if (enable) {
+            when(mActiveModeWarden.getInternetConnectivityClientModeManagers())
+                    .thenReturn(Arrays.asList(mPrimaryClientModeManager));
             modeChangeCallback.onActiveModeManagerAdded(mPrimaryClientModeManager);
         } else {
+            when(mActiveModeWarden.getInternetConnectivityClientModeManagers())
+                    .thenReturn(Arrays.asList());
             modeChangeCallback.onActiveModeManagerRemoved(mPrimaryClientModeManager);
         }
     }