• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.wifi;
18 
19 import static android.net.wifi.WifiManager.IFACE_IP_MODE_LOCAL_ONLY;
20 import static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED;
21 import static android.net.wifi.WifiManager.SAP_START_FAILURE_GENERAL;
22 import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED;
23 import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED;
24 import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING;
25 import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED;
26 import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING;
27 import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN;
28 
29 import static com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_LOCAL_ONLY;
30 import static com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_PRIMARY;
31 import static com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_SCAN_ONLY;
32 import static com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_SECONDARY_LONG_LIVED;
33 import static com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_SECONDARY_TRANSIENT;
34 import static com.android.server.wifi.ActiveModeManager.ROLE_SOFTAP_TETHERED;
35 import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_NATIVE_SUPPORTED_STA_BANDS;
36 
37 import android.annotation.NonNull;
38 import android.annotation.Nullable;
39 import android.content.BroadcastReceiver;
40 import android.content.Context;
41 import android.content.Intent;
42 import android.content.IntentFilter;
43 import android.content.pm.PackageManager;
44 import android.database.ContentObserver;
45 import android.location.LocationManager;
46 import android.net.Network;
47 import android.net.wifi.ISubsystemRestartCallback;
48 import android.net.wifi.IWifiConnectedNetworkScorer;
49 import android.net.wifi.IWifiNetworkStateChangedListener;
50 import android.net.wifi.IWifiStateChangedListener;
51 import android.net.wifi.SoftApCapability;
52 import android.net.wifi.SoftApConfiguration;
53 import android.net.wifi.SoftApState;
54 import android.net.wifi.WifiConfiguration;
55 import android.net.wifi.WifiContext;
56 import android.net.wifi.WifiInfo;
57 import android.net.wifi.WifiManager;
58 import android.net.wifi.WifiManager.DeviceMobilityState;
59 import android.net.wifi.WifiScanner;
60 import android.net.wifi.util.WifiResourceCache;
61 import android.os.BatteryStatsManager;
62 import android.os.Build;
63 import android.os.Handler;
64 import android.os.IBinder;
65 import android.os.Looper;
66 import android.os.Message;
67 import android.os.Process;
68 import android.os.RemoteCallbackList;
69 import android.os.RemoteException;
70 import android.os.UserHandle;
71 import android.os.UserManager;
72 import android.os.WorkSource;
73 import android.provider.Settings;
74 import android.telephony.TelephonyManager;
75 import android.text.TextUtils;
76 import android.util.ArraySet;
77 import android.util.LocalLog;
78 import android.util.Log;
79 import android.util.Pair;
80 
81 import androidx.annotation.Keep;
82 
83 import com.android.internal.annotations.GuardedBy;
84 import com.android.internal.annotations.VisibleForTesting;
85 import com.android.internal.util.IState;
86 import com.android.internal.util.Preconditions;
87 import com.android.internal.util.Protocol;
88 import com.android.internal.util.StateMachine;
89 import com.android.modules.utils.build.SdkLevel;
90 import com.android.server.wifi.ActiveModeManager.ClientConnectivityRole;
91 import com.android.server.wifi.ActiveModeManager.ClientInternetConnectivityRole;
92 import com.android.server.wifi.ActiveModeManager.ClientRole;
93 import com.android.server.wifi.ActiveModeManager.SoftApRole;
94 import com.android.server.wifi.util.ApConfigUtil;
95 import com.android.server.wifi.util.LastCallerInfoManager;
96 import com.android.server.wifi.util.NativeUtil;
97 import com.android.server.wifi.util.WifiPermissionsUtil;
98 import com.android.wifi.flags.FeatureFlags;
99 import com.android.wifi.resources.R;
100 
101 import java.io.FileDescriptor;
102 import java.io.PrintWriter;
103 import java.util.ArrayDeque;
104 import java.util.ArrayList;
105 import java.util.BitSet;
106 import java.util.Collection;
107 import java.util.Collections;
108 import java.util.List;
109 import java.util.Objects;
110 import java.util.Set;
111 import java.util.concurrent.Executor;
112 import java.util.concurrent.atomic.AtomicInteger;
113 import java.util.stream.Collectors;
114 import java.util.stream.Stream;
115 
116 /**
117  * This class provides the implementation for different WiFi operating modes.
118  */
119 public class ActiveModeWarden {
120     private static final String TAG = "WifiActiveModeWarden";
121     private static final String STATE_MACHINE_EXITED_STATE_NAME = "STATE_MACHINE_EXITED";
122     public static final WorkSource INTERNAL_REQUESTOR_WS = new WorkSource(Process.WIFI_UID);
123 
124     // Holder for active mode managers
125     private final Set<ConcreteClientModeManager> mClientModeManagers = new ArraySet<>();
126     private final Set<SoftApManager> mSoftApManagers = new ArraySet<>();
127 
128     private final Set<ModeChangeCallback> mCallbacks = new ArraySet<>();
129     private final Set<PrimaryClientModeManagerChangedCallback> mPrimaryChangedCallbacks =
130             new ArraySet<>();
131     // DefaultModeManager used to service API calls when there are no active client mode managers.
132     private final DefaultClientModeManager mDefaultClientModeManager;
133     private final WifiInjector mWifiInjector;
134     private final Looper mLooper;
135     private final Handler mHandler;
136     private final WifiContext mContext;
137     private final WifiDiagnostics mWifiDiagnostics;
138     private final WifiSettingsStore mSettingsStore;
139     private final FrameworkFacade mFacade;
140     private final WifiPermissionsUtil mWifiPermissionsUtil;
141     private final BatteryStatsManager mBatteryStatsManager;
142     private final ScanRequestProxy mScanRequestProxy;
143     private final WifiNative mWifiNative;
144     private final WifiController mWifiController;
145     private final Graveyard mGraveyard;
146     private final WifiMetrics mWifiMetrics;
147     private final ExternalScoreUpdateObserverProxy mExternalScoreUpdateObserverProxy;
148     private final DppManager mDppManager;
149     private final UserManager mUserManager;
150     private final LastCallerInfoManager mLastCallerInfoManager;
151     private final WifiGlobals mWifiGlobals;
152     private final FeatureFlags mFeatureFlags;
153 
154     private WifiServiceImpl.SoftApCallbackInternal mSoftApCallback;
155     private WifiServiceImpl.SoftApCallbackInternal mLohsCallback;
156 
157     private final RemoteCallbackList<ISubsystemRestartCallback> mRestartCallbacks =
158             new RemoteCallbackList<>();
159     private final RemoteCallbackList<IWifiNetworkStateChangedListener>
160             mWifiNetworkStateChangedListeners = new RemoteCallbackList<>();
161     private final RemoteCallbackList<IWifiStateChangedListener> mWifiStateChangedListeners =
162             new RemoteCallbackList<>();
163 
164     private boolean mIsMultiplePrimaryBugreportTaken = false;
165     private boolean mIsShuttingdown = false;
166     private boolean mVerboseLoggingEnabled = false;
167     private boolean mAllowRootToGetLocalOnlyCmm = true;
168     private @DeviceMobilityState int mDeviceMobilityState =
169             WifiManager.DEVICE_MOBILITY_STATE_UNKNOWN;
170     /** Cache to store the external scorer for primary and secondary (MBB) client mode manager. */
171     @Nullable private Pair<IBinder, IWifiConnectedNetworkScorer> mClientModeManagerScorer;
172     private int mScorerUid;
173 
174     @Nullable
175     private ConcreteClientModeManager mLastPrimaryClientModeManager = null;
176 
177     @Nullable
178     private WorkSource mLastPrimaryClientModeManagerRequestorWs = null;
179     @Nullable
180     private WorkSource mLastScanOnlyClientModeManagerRequestorWs = null;
181     private AtomicInteger mBandsSupported = new AtomicInteger(0);
182     // Mutex lock between service Api binder thread and Wifi main thread
183     private final Object mServiceApiLock = new Object();
184     @GuardedBy("mServiceApiLock")
185     private Network mCurrentNetwork;
186     @GuardedBy("mServiceApiLock")
187     private WifiInfo mCurrentConnectionInfo = new WifiInfo();
188     @GuardedBy("mServiceApiLock")
189     private BitSet mSupportedFeatureSet = new BitSet();
190 
191     @GuardedBy("mServiceApiLock")
192     private final ArraySet<WorkSource> mRequestWs = new ArraySet<>();
193 
194     /**
195      * One of  {@link WifiManager#WIFI_STATE_DISABLED},
196      * {@link WifiManager#WIFI_STATE_DISABLING},
197      * {@link WifiManager#WIFI_STATE_ENABLED},
198      * {@link WifiManager#WIFI_STATE_ENABLING},
199      * {@link WifiManager#WIFI_STATE_UNKNOWN}
200      */
201     private final AtomicInteger mWifiState = new AtomicInteger(WIFI_STATE_DISABLED);
202 
203     private ContentObserver mSatelliteModeContentObserver;
204     private final WifiResourceCache mResourceCache;
205 
206     /**
207      * Method that allows the active ClientModeManager to set the wifi state that is
208      * retrieved by API calls. Only primary ClientModeManager should call this method when state
209      * changes
210      * @param newState new state to set, invalid states are ignored.
211      */
setWifiStateForApiCalls(int newState)212     public void setWifiStateForApiCalls(int newState) {
213         switch (newState) {
214             case WIFI_STATE_DISABLING:
215             case WIFI_STATE_DISABLED:
216             case WIFI_STATE_ENABLING:
217             case WIFI_STATE_ENABLED:
218             case WIFI_STATE_UNKNOWN:
219                 if (mVerboseLoggingEnabled) {
220                     Log.d(TAG, "setting wifi state to: " + newState);
221                 }
222                 if (mWifiState.get() != newState) {
223                     mWifiState.set(newState);
224                     notifyRemoteWifiStateChangedListeners();
225                 }
226                 break;
227             default:
228                 Log.d(TAG, "attempted to set an invalid state: " + newState);
229                 break;
230         }
231     }
232 
233     /**
234      * Get the request WorkSource for secondary CMM
235      *
236      * @return the WorkSources of the current secondary CMMs
237      */
getSecondaryRequestWs()238     public Set<WorkSource> getSecondaryRequestWs() {
239         synchronized (mServiceApiLock) {
240             return new ArraySet<>(mRequestWs);
241         }
242     }
243 
getWifiStateName()244     private String getWifiStateName() {
245         switch (mWifiState.get()) {
246             case WIFI_STATE_DISABLING:
247                 return "disabling";
248             case WIFI_STATE_DISABLED:
249                 return "disabled";
250             case WIFI_STATE_ENABLING:
251                 return "enabling";
252             case WIFI_STATE_ENABLED:
253                 return "enabled";
254             case WIFI_STATE_UNKNOWN:
255                 return "unknown state";
256             default:
257                 return "[invalid state]";
258         }
259     }
260 
261     /**
262      * Method used by WifiServiceImpl to get the current state of Wifi for API calls.
263      * The Wifi state is a global state of the device, which equals to the state of the primary STA.
264      * This method must be thread safe.
265      */
getWifiState()266     public int getWifiState() {
267         return mWifiState.get();
268     }
269 
270     /**
271      * Notify changes in PowerManager#isDeviceIdleMode
272      */
onIdleModeChanged(boolean isIdle)273     public void onIdleModeChanged(boolean isIdle) {
274         // only client mode managers need to get notified for now to consider enabling/disabling
275         // firmware roaming
276         for (ClientModeManager cmm : mClientModeManagers) {
277             cmm.onIdleModeChanged(isIdle);
278         }
279     }
280 
281     /**
282      * See {@link WifiManager#addWifiStateChangedListener(Executor, WifiStateChangedListener)}
283      */
addWifiStateChangedListener(@onNull IWifiStateChangedListener listener)284     public void addWifiStateChangedListener(@NonNull IWifiStateChangedListener listener) {
285         mWifiStateChangedListeners.register(listener);
286         try {
287             listener.onWifiStateChanged();
288         } catch (RemoteException e) {
289             Log.e(TAG, "onWifiStateChanged: remote exception -- " + e);
290         }
291     }
292 
293     /**
294      * See {@link WifiManager#removeWifiStateChangedListener(WifiStateChangedListener)}
295      */
removeWifiStateChangedListener(@onNull IWifiStateChangedListener listener)296     public void removeWifiStateChangedListener(@NonNull IWifiStateChangedListener listener) {
297         mWifiStateChangedListeners.unregister(listener);
298     }
299 
notifyRemoteWifiStateChangedListeners()300     private void notifyRemoteWifiStateChangedListeners() {
301         final int itemCount = mWifiStateChangedListeners.beginBroadcast();
302         for (int i = 0; i < itemCount; i++) {
303             try {
304                 mWifiStateChangedListeners.getBroadcastItem(i).onWifiStateChanged();
305             } catch (RemoteException e) {
306                 Log.e(TAG, "onWifiStateChanged: remote exception -- " + e);
307             }
308         }
309         mWifiStateChangedListeners.finishBroadcast();
310     }
311 
312     /**
313      * Called from WifiServiceImpl to register a callback for notifications from SoftApManager
314      */
registerSoftApCallback(@onNull WifiServiceImpl.SoftApCallbackInternal callback)315     public void registerSoftApCallback(@NonNull WifiServiceImpl.SoftApCallbackInternal callback) {
316         mSoftApCallback = callback;
317     }
318 
319     /**
320      * Called from WifiServiceImpl to register a callback for notifications from SoftApManager
321      * for local-only hotspot.
322      */
registerLohsCallback(@onNull WifiServiceImpl.SoftApCallbackInternal callback)323     public void registerLohsCallback(@NonNull WifiServiceImpl.SoftApCallbackInternal callback) {
324         mLohsCallback = callback;
325     }
326 
327     /**
328      * Callbacks for indicating any mode manager changes to the rest of the system.
329      */
330     public interface ModeChangeCallback {
331         /**
332          * Invoked when new mode manager is added.
333          *
334          * @param activeModeManager Instance of {@link ActiveModeManager}.
335          */
onActiveModeManagerAdded(@onNull ActiveModeManager activeModeManager)336         void onActiveModeManagerAdded(@NonNull ActiveModeManager activeModeManager);
337 
338         /**
339          * Invoked when a mode manager is removed.
340          *
341          * @param activeModeManager Instance of {@link ActiveModeManager}.
342          */
onActiveModeManagerRemoved(@onNull ActiveModeManager activeModeManager)343         void onActiveModeManagerRemoved(@NonNull ActiveModeManager activeModeManager);
344 
345         /**
346          * Invoked when an existing mode manager's role is changed.
347          *
348          * @param activeModeManager Instance of {@link ActiveModeManager}.
349          */
onActiveModeManagerRoleChanged(@onNull ActiveModeManager activeModeManager)350         void onActiveModeManagerRoleChanged(@NonNull ActiveModeManager activeModeManager);
351     }
352 
353     /** Called when the primary ClientModeManager changes. */
354     public interface PrimaryClientModeManagerChangedCallback {
355         /**
356          * Note: The current implementation for changing primary CMM is not atomic (due to setRole()
357          * needing to go through StateMachine, which is async). Thus, when the primary CMM changes,
358          * the sequence of calls looks like this:
359          * 1. onChange(prevPrimaryCmm, null)
360          * 2. onChange(null, newPrimaryCmm)
361          * Nevertheless, at run time, these two calls should occur in rapid succession.
362          *
363          * @param prevPrimaryClientModeManager the previous primary ClientModeManager, or null if
364          *                                     there was no previous primary (e.g. Wifi was off).
365          * @param newPrimaryClientModeManager the new primary ClientModeManager, or null if there is
366          *                                    no longer a primary (e.g. Wifi was turned off).
367          */
onChange( @ullable ConcreteClientModeManager prevPrimaryClientModeManager, @Nullable ConcreteClientModeManager newPrimaryClientModeManager)368         void onChange(
369                 @Nullable ConcreteClientModeManager prevPrimaryClientModeManager,
370                 @Nullable ConcreteClientModeManager newPrimaryClientModeManager);
371     }
372 
373     /**
374      * Keep stopped {@link ActiveModeManager} instances so that they can be dumped to aid debugging.
375      *
376      * TODO(b/160283853): Find a smarter way to evict old ActiveModeManagers
377      */
378     private static class Graveyard {
379         private static final int INSTANCES_TO_KEEP = 3;
380 
381         private final ArrayDeque<ConcreteClientModeManager> mClientModeManagers =
382                 new ArrayDeque<>();
383         private final ArrayDeque<SoftApManager> mSoftApManagers = new ArrayDeque<>();
384 
385         /**
386          * Add this stopped {@link ConcreteClientModeManager} to the graveyard, and evict the oldest
387          * ClientModeManager if the graveyard is full.
388          */
inter(ConcreteClientModeManager clientModeManager)389         void inter(ConcreteClientModeManager clientModeManager) {
390             if (mClientModeManagers.size() == INSTANCES_TO_KEEP) {
391                 mClientModeManagers.removeFirst();
392             }
393             mClientModeManagers.addLast(clientModeManager);
394         }
395 
396         /**
397          * Add this stopped {@link SoftApManager} to the graveyard, and evict the oldest
398          * SoftApManager if the graveyard is full.
399          */
inter(SoftApManager softApManager)400         void inter(SoftApManager softApManager) {
401             if (mSoftApManagers.size() == INSTANCES_TO_KEEP) {
402                 mSoftApManagers.removeFirst();
403             }
404             mSoftApManagers.addLast(softApManager);
405         }
406 
407         /** Dump the contents of the graveyard. */
dump(FileDescriptor fd, PrintWriter pw, String[] args)408         void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
409             pw.println("Dump of ActiveModeWarden.Graveyard");
410             pw.println("Stopped ClientModeManagers: " + mClientModeManagers.size() + " total");
411             for (ConcreteClientModeManager clientModeManager : mClientModeManagers) {
412                 clientModeManager.dump(fd, pw, args);
413             }
414             pw.println("Stopped SoftApManagers: " + mSoftApManagers.size() + " total");
415             for (SoftApManager softApManager : mSoftApManagers) {
416                 softApManager.dump(fd, pw, args);
417             }
418             pw.println();
419         }
420     }
421 
ActiveModeWarden(WifiInjector wifiInjector, Looper looper, WifiNative wifiNative, DefaultClientModeManager defaultClientModeManager, BatteryStatsManager batteryStatsManager, WifiDiagnostics wifiDiagnostics, WifiContext context, WifiSettingsStore settingsStore, FrameworkFacade facade, WifiPermissionsUtil wifiPermissionsUtil, WifiMetrics wifiMetrics, ExternalScoreUpdateObserverProxy externalScoreUpdateObserverProxy, DppManager dppManager, WifiGlobals wifiGlobals)422     ActiveModeWarden(WifiInjector wifiInjector,
423             Looper looper,
424             WifiNative wifiNative,
425             DefaultClientModeManager defaultClientModeManager,
426             BatteryStatsManager batteryStatsManager,
427             WifiDiagnostics wifiDiagnostics,
428             WifiContext context,
429             WifiSettingsStore settingsStore,
430             FrameworkFacade facade,
431             WifiPermissionsUtil wifiPermissionsUtil,
432             WifiMetrics wifiMetrics,
433             ExternalScoreUpdateObserverProxy externalScoreUpdateObserverProxy,
434             DppManager dppManager,
435             WifiGlobals wifiGlobals) {
436         mWifiInjector = wifiInjector;
437         mLooper = looper;
438         mHandler = new Handler(looper);
439         mContext = context;
440         mResourceCache = mContext.getResourceCache();
441         mWifiDiagnostics = wifiDiagnostics;
442         mSettingsStore = settingsStore;
443         mFacade = facade;
444         mWifiPermissionsUtil = wifiPermissionsUtil;
445         mDefaultClientModeManager = defaultClientModeManager;
446         mBatteryStatsManager = batteryStatsManager;
447         mScanRequestProxy = wifiInjector.getScanRequestProxy();
448         mWifiNative = wifiNative;
449         mWifiMetrics = wifiMetrics;
450         mWifiController = new WifiController();
451         mExternalScoreUpdateObserverProxy = externalScoreUpdateObserverProxy;
452         mDppManager = dppManager;
453         mGraveyard = new Graveyard();
454         mUserManager = mWifiInjector.getUserManager();
455         mLastCallerInfoManager = mWifiInjector.getLastCallerInfoManager();
456         mWifiGlobals = wifiGlobals;
457         mFeatureFlags = mWifiInjector.getDeviceConfigFacade().getFeatureFlags();
458 
459         wifiNative.registerStatusListener(isReady -> {
460             if (!isReady && !mIsShuttingdown) {
461                 Log.e(TAG, "One of the native daemons died. Triggering recovery");
462                 mWifiInjector.getWifiConfigManager().writeDataToStorage();
463                 wifiDiagnostics.triggerBugReportDataCapture(
464                         WifiDiagnostics.REPORT_REASON_WIFINATIVE_FAILURE);
465 
466                 // immediately trigger SelfRecovery if we receive a notice about an
467                 // underlying daemon failure
468                 // Note: SelfRecovery has a circular dependency with ActiveModeWarden and is
469                 // instantiated after ActiveModeWarden, so use WifiInjector to get the instance
470                 // instead of directly passing in SelfRecovery in the constructor.
471                     mWifiInjector.getSelfRecovery().trigger(SelfRecovery.REASON_WIFINATIVE_FAILURE);
472             }
473         });
474 
475         registerPrimaryClientModeManagerChangedCallback(
476                 (prevPrimaryClientModeManager, newPrimaryClientModeManager) -> {
477                     // TODO (b/181363901): We can always propagate the external scorer to all
478                     // ClientModeImpl instances. WifiScoreReport already handles skipping external
479                     // scorer notification for local only & restricted STA + STA use-cases. For MBB
480                     // use-case, we may want the external scorer to be notified.
481                     if (prevPrimaryClientModeManager != null) {
482                         prevPrimaryClientModeManager.clearWifiConnectedNetworkScorer();
483                     }
484                     if (newPrimaryClientModeManager != null && mClientModeManagerScorer != null) {
485                         newPrimaryClientModeManager.setWifiConnectedNetworkScorer(
486                                 mClientModeManagerScorer.first, mClientModeManagerScorer.second,
487                                 mScorerUid);
488                     }
489                 });
490     }
491 
invokeOnAddedCallbacks(@onNull ActiveModeManager activeModeManager)492     private void invokeOnAddedCallbacks(@NonNull ActiveModeManager activeModeManager) {
493         if (mVerboseLoggingEnabled) {
494             Log.v(TAG, "ModeManager added " + activeModeManager);
495         }
496         for (ModeChangeCallback callback : mCallbacks) {
497             callback.onActiveModeManagerAdded(activeModeManager);
498         }
499     }
500 
invokeOnRemovedCallbacks(@onNull ActiveModeManager activeModeManager)501     private void invokeOnRemovedCallbacks(@NonNull ActiveModeManager activeModeManager) {
502         if (mVerboseLoggingEnabled) {
503             Log.v(TAG, "ModeManager removed " + activeModeManager);
504         }
505         for (ModeChangeCallback callback : mCallbacks) {
506             callback.onActiveModeManagerRemoved(activeModeManager);
507         }
508     }
509 
invokeOnRoleChangedCallbacks(@onNull ActiveModeManager activeModeManager)510     private void invokeOnRoleChangedCallbacks(@NonNull ActiveModeManager activeModeManager) {
511         if (mVerboseLoggingEnabled) {
512             Log.v(TAG, "ModeManager role changed " + activeModeManager);
513         }
514         for (ModeChangeCallback callback : mCallbacks) {
515             callback.onActiveModeManagerRoleChanged(activeModeManager);
516         }
517     }
518 
invokeOnPrimaryClientModeManagerChangedCallbacks( @ullable ConcreteClientModeManager prevPrimaryClientModeManager, @Nullable ConcreteClientModeManager newPrimaryClientModeManager)519     private void invokeOnPrimaryClientModeManagerChangedCallbacks(
520             @Nullable ConcreteClientModeManager prevPrimaryClientModeManager,
521             @Nullable ConcreteClientModeManager newPrimaryClientModeManager) {
522         if (mVerboseLoggingEnabled) {
523             Log.v(TAG, "Primary ClientModeManager changed from " + prevPrimaryClientModeManager
524                     + " to " + newPrimaryClientModeManager);
525         }
526 
527         for (PrimaryClientModeManagerChangedCallback callback : mPrimaryChangedCallbacks) {
528             callback.onChange(prevPrimaryClientModeManager, newPrimaryClientModeManager);
529         }
530     }
531 
532     /**
533      * Used for testing with wifi shell command. If enabled the root will be able to request for a
534      * secondary local-only CMM when commands like add-request is used. If disabled, add-request
535      * will fallback to using the primary CMM.
536      */
allowRootToGetLocalOnlyCmm(boolean enabled)537     public void allowRootToGetLocalOnlyCmm(boolean enabled) {
538         mAllowRootToGetLocalOnlyCmm = enabled;
539     }
540 
541     /**
542      * Enable verbose logging.
543      */
enableVerboseLogging(boolean verbose)544     public void enableVerboseLogging(boolean verbose) {
545         mVerboseLoggingEnabled = verbose;
546         for (ActiveModeManager modeManager : getActiveModeManagers()) {
547             modeManager.enableVerboseLogging(verbose);
548         }
549     }
550 
551     /**
552      * See {@link android.net.wifi.WifiManager#setWifiConnectedNetworkScorer(Executor,
553      * WifiManager.WifiConnectedNetworkScorer)}
554      */
setWifiConnectedNetworkScorer(IBinder binder, IWifiConnectedNetworkScorer scorer, int callerUid)555     public boolean setWifiConnectedNetworkScorer(IBinder binder,
556             IWifiConnectedNetworkScorer scorer, int callerUid) {
557         try {
558             scorer.onSetScoreUpdateObserver(mExternalScoreUpdateObserverProxy);
559         } catch (RemoteException e) {
560             Log.e(TAG, "Unable to set score update observer " + scorer, e);
561             return false;
562         }
563         mClientModeManagerScorer = Pair.create(binder, scorer);
564         mScorerUid = callerUid;
565         return getPrimaryClientModeManager().setWifiConnectedNetworkScorer(binder, scorer,
566                 callerUid);
567     }
568 
569     /**
570      * See {@link WifiManager#clearWifiConnectedNetworkScorer()}
571      */
clearWifiConnectedNetworkScorer()572     public void clearWifiConnectedNetworkScorer() {
573         mClientModeManagerScorer = null;
574         mScorerUid = Process.WIFI_UID;
575         getPrimaryClientModeManager().clearWifiConnectedNetworkScorer();
576     }
577 
578     /**
579      * Register for mode change callbacks.
580      */
registerModeChangeCallback(@onNull ModeChangeCallback callback)581     public void registerModeChangeCallback(@NonNull ModeChangeCallback callback) {
582         if (callback == null) {
583             Log.wtf(TAG, "Cannot register a null ModeChangeCallback");
584             return;
585         }
586         mCallbacks.add(callback);
587     }
588 
589     /**
590      * Unregister mode change callback.
591      */
unregisterModeChangeCallback(@onNull ModeChangeCallback callback)592     public void unregisterModeChangeCallback(@NonNull ModeChangeCallback callback) {
593         if (callback == null) {
594             Log.wtf(TAG, "Cannot unregister a null ModeChangeCallback");
595             return;
596         }
597         mCallbacks.remove(callback);
598     }
599 
600     /** Register for primary ClientModeManager changed callbacks. */
registerPrimaryClientModeManagerChangedCallback( @onNull PrimaryClientModeManagerChangedCallback callback)601     public void registerPrimaryClientModeManagerChangedCallback(
602             @NonNull PrimaryClientModeManagerChangedCallback callback) {
603         if (callback == null) {
604             Log.wtf(TAG, "Cannot register a null PrimaryClientModeManagerChangedCallback");
605             return;
606         }
607         mPrimaryChangedCallbacks.add(callback);
608         // If there is already a primary CMM when registering, send a callback with the info.
609         ConcreteClientModeManager cm = getPrimaryClientModeManagerNullable();
610         if (cm != null) callback.onChange(null, cm);
611     }
612 
613     /** Unregister for primary ClientModeManager changed callbacks. */
unregisterPrimaryClientModeManagerChangedCallback( @onNull PrimaryClientModeManagerChangedCallback callback)614     public void unregisterPrimaryClientModeManagerChangedCallback(
615             @NonNull PrimaryClientModeManagerChangedCallback callback) {
616         if (callback == null) {
617             Log.wtf(TAG, "Cannot unregister a null PrimaryClientModeManagerChangedCallback");
618             return;
619         }
620         mPrimaryChangedCallbacks.remove(callback);
621     }
622 
623     /**
624      * Notify that device is shutting down
625      * Keep it simple and don't add collection access codes
626      * to avoid concurrentModificationException when it is directly called from a different thread
627      */
notifyShuttingDown()628     public void notifyShuttingDown() {
629         mIsShuttingdown = true;
630     }
631 
632     /** @return Returns whether device is shutting down */
isShuttingDown()633     public boolean isShuttingDown() {
634         return mIsShuttingdown;
635     }
636 
637     /**
638      * @return Returns whether we can create more client mode managers or not.
639      */
canRequestMoreClientModeManagersInRole(@onNull WorkSource requestorWs, @NonNull ClientRole clientRole, boolean didUserApprove)640     public boolean canRequestMoreClientModeManagersInRole(@NonNull WorkSource requestorWs,
641             @NonNull ClientRole clientRole, boolean didUserApprove) {
642         WorkSource ifCreatorWs = new WorkSource(requestorWs);
643         if (didUserApprove) {
644             // If user select to connect from the UI, promote the priority
645             ifCreatorWs.add(mFacade.getSettingsWorkSource(mContext));
646         }
647         if (!mWifiNative.isItPossibleToCreateStaIface(ifCreatorWs)) {
648             return false;
649         }
650         if (clientRole == ROLE_CLIENT_LOCAL_ONLY) {
651             if (!mResourceCache.getBoolean(
652                     R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled)) {
653                 return false;
654             }
655             final int uid = requestorWs.getUid(0);
656             final String packageName = requestorWs.getPackageName(0);
657             // For peer to peer use-case, only allow secondary STA if the app is targeting S SDK
658             // or is a system app to provide backward compatibility.
659             return mWifiPermissionsUtil.isSystem(packageName, uid)
660                     || !mWifiPermissionsUtil.isTargetSdkLessThan(
661                             packageName, Build.VERSION_CODES.S, uid);
662         }
663         if (clientRole == ROLE_CLIENT_SECONDARY_TRANSIENT) {
664             return mResourceCache.getBoolean(
665                     R.bool.config_wifiMultiStaNetworkSwitchingMakeBeforeBreakEnabled);
666         }
667         if (clientRole == ROLE_CLIENT_SECONDARY_LONG_LIVED) {
668             return mResourceCache.getBoolean(
669                     R.bool.config_wifiMultiStaRestrictedConcurrencyEnabled)
670                     || mResourceCache.getBoolean(
671                     R.bool.config_wifiMultiStaMultiInternetConcurrencyEnabled);
672         }
673         Log.e(TAG, "Unrecognized role=" + clientRole);
674         return false;
675     }
676 
677     /**
678      * @return Returns whether we can create more SoftAp managers or not.
679      */
canRequestMoreSoftApManagers(@onNull WorkSource requestorWs)680     public boolean canRequestMoreSoftApManagers(@NonNull WorkSource requestorWs) {
681         return mWifiNative.isItPossibleToCreateApIface(requestorWs);
682     }
683 
684     /**
685      * @return Returns whether the device can support at least two concurrent client mode managers
686      * and the local only use-case is enabled.
687      */
isStaStaConcurrencySupportedForLocalOnlyConnections()688     public boolean isStaStaConcurrencySupportedForLocalOnlyConnections() {
689         return mWifiNative.isStaStaConcurrencySupported()
690                 && mResourceCache.getBoolean(
691                         R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled);
692     }
693 
694     /**
695      * @return Returns whether the device can support at least two concurrent client mode managers
696      * and the mbb wifi switching is enabled.
697      */
isStaStaConcurrencySupportedForMbb()698     public boolean isStaStaConcurrencySupportedForMbb() {
699         return mWifiNative.isStaStaConcurrencySupported()
700                 && mResourceCache.getBoolean(
701                         R.bool.config_wifiMultiStaNetworkSwitchingMakeBeforeBreakEnabled);
702     }
703 
704     /**
705      * @return Returns whether the device can support at least two concurrent client mode managers
706      * and the restricted use-case is enabled.
707      */
isStaStaConcurrencySupportedForRestrictedConnections()708     public boolean isStaStaConcurrencySupportedForRestrictedConnections() {
709         return mWifiNative.isStaStaConcurrencySupported()
710                 && mResourceCache.getBoolean(
711                         R.bool.config_wifiMultiStaRestrictedConcurrencyEnabled);
712     }
713 
714     /**
715      * @return Returns whether the device can support at least two concurrent client mode managers
716      * and the multi internet use-case is enabled.
717      */
isStaStaConcurrencySupportedForMultiInternet()718     public boolean isStaStaConcurrencySupportedForMultiInternet() {
719         return mWifiNative.isStaStaConcurrencySupported()
720                 && mResourceCache.getBoolean(
721                         R.bool.config_wifiMultiStaMultiInternetConcurrencyEnabled);
722     }
723 
724     /** Begin listening to broadcasts and start the internal state machine. */
start()725     public void start() {
726         BroadcastReceiver locationChangeReceiver = new BroadcastReceiver() {
727             @Override
728             public void onReceive(Context context, Intent intent) {
729                 // Location mode has been toggled...  trigger with the scan change
730                 // update to make sure we are in the correct mode
731                 scanAlwaysModeChanged();
732             }
733         };
734 
735         BroadcastReceiver airplaneChangedReceiver = new BroadcastReceiver() {
736             @Override
737             public void onReceive(Context context, Intent intent) {
738                 boolean airplaneModeUpdated = mSettingsStore.updateAirplaneModeTracker();
739                 boolean userRestrictionSet =
740                         SdkLevel.isAtLeastT() && mUserManager.hasUserRestrictionForUser(
741                                 UserManager.DISALLOW_CHANGE_WIFI_STATE,
742                                 UserHandle.getUserHandleForUid(Process.SYSTEM_UID));
743                 if (!userRestrictionSet && airplaneModeUpdated) {
744                     mSettingsStore.handleAirplaneModeToggled();
745                     airplaneModeToggled();
746                 }
747             }
748         };
749 
750         BroadcastReceiver emergencyCallbackModeChangedReceiver = new BroadcastReceiver() {
751             @Override
752             public void onReceive(Context context, Intent intent) {
753                 boolean emergencyMode =
754                         intent.getBooleanExtra(TelephonyManager.EXTRA_PHONE_IN_ECM_STATE, false);
755                 emergencyCallbackModeChanged(emergencyMode);
756             }
757         };
758 
759         BroadcastReceiver emergencyCallStateChangedReceiver = new BroadcastReceiver() {
760             @Override
761             public void onReceive(Context context, Intent intent) {
762                 boolean inCall = intent.getBooleanExtra(
763                         TelephonyManager.EXTRA_PHONE_IN_EMERGENCY_CALL, false);
764                 emergencyCallStateChanged(inCall);
765             }
766         };
767 
768 
769         mContext.registerReceiverForAllUsers(locationChangeReceiver,
770                 new IntentFilter(LocationManager.MODE_CHANGED_ACTION), null, mHandler);
771         boolean trackEmergencyCallState = mResourceCache.getBoolean(
772                 R.bool.config_wifi_turn_off_during_emergency_call);
773         if (mFeatureFlags.monitorIntentForAllUsers()) {
774             mContext.registerReceiverForAllUsers(airplaneChangedReceiver,
775                     new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED), null, mHandler);
776             mContext.registerReceiverForAllUsers(emergencyCallbackModeChangedReceiver,
777                     new IntentFilter(TelephonyManager.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED),
778                     null, mHandler);
779             if (trackEmergencyCallState) {
780                 mContext.registerReceiverForAllUsers(emergencyCallStateChangedReceiver,
781                         new IntentFilter(TelephonyManager.ACTION_EMERGENCY_CALL_STATE_CHANGED),
782                         null, mHandler);
783             }
784         } else {
785             mContext.registerReceiver(airplaneChangedReceiver,
786                     new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
787             mContext.registerReceiver(emergencyCallbackModeChangedReceiver,
788                     new IntentFilter(TelephonyManager.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED));
789             if (trackEmergencyCallState) {
790                 mContext.registerReceiver(emergencyCallStateChangedReceiver,
791                         new IntentFilter(TelephonyManager.ACTION_EMERGENCY_CALL_STATE_CHANGED));
792             }
793         }
794         mWifiGlobals.setD2dStaConcurrencySupported(
795                 mWifiNative.isP2pStaConcurrencySupported()
796                         || mWifiNative.isNanStaConcurrencySupported());
797         // Initialize the supported feature set.
798         setSupportedFeatureSet(mWifiNative.getSupportedFeatureSet(null),
799                 mWifiNative.isStaApConcurrencySupported(),
800                 mWifiNative.isStaStaConcurrencySupported());
801 
802         mSatelliteModeContentObserver = new ContentObserver(mHandler) {
803             @Override
804             public void onChange(boolean selfChange) {
805                 handleSatelliteModeChange();
806             }
807         };
808         mFacade.registerContentObserver(
809                 mContext,
810                 Settings.Global.getUriFor(WifiSettingsStore.SETTINGS_SATELLITE_MODE_RADIOS),
811                 false, mSatelliteModeContentObserver);
812         mFacade.registerContentObserver(
813                 mContext,
814                 Settings.Global.getUriFor(WifiSettingsStore.SETTINGS_SATELLITE_MODE_ENABLED),
815                 false, mSatelliteModeContentObserver);
816 
817         mWifiController.start();
818     }
819 
820     /** Disable Wifi for recovery purposes. */
recoveryDisableWifi()821     public void recoveryDisableWifi() {
822         mWifiController.sendMessage(WifiController.CMD_RECOVERY_DISABLE_WIFI);
823     }
824 
825     /**
826      * Restart Wifi for recovery purposes.
827      * @param reason One of {@link SelfRecovery.RecoveryReason}
828      */
recoveryRestartWifi(@elfRecovery.RecoveryReason int reason, boolean requestBugReport)829     public void recoveryRestartWifi(@SelfRecovery.RecoveryReason int reason,
830             boolean requestBugReport) {
831         mWifiController.sendMessage(WifiController.CMD_RECOVERY_RESTART_WIFI, reason,
832                 requestBugReport ? 1 : 0, SelfRecovery.getRecoveryReasonAsString(reason));
833     }
834 
835     /**
836      * register a callback to monitor the progress of Wi-Fi subsystem operation (started/finished)
837      * - started via {@link #recoveryRestartWifi(int, String, boolean)}.
838      */
registerSubsystemRestartCallback(ISubsystemRestartCallback callback)839     public boolean registerSubsystemRestartCallback(ISubsystemRestartCallback callback) {
840         return mRestartCallbacks.register(callback);
841     }
842 
843     /**
844      * unregister a callback to monitor the progress of Wi-Fi subsystem operation (started/finished)
845      * - started via {@link #recoveryRestartWifi(int, String, boolean)}. Callback is registered via
846      * {@link #registerSubsystemRestartCallback(ISubsystemRestartCallback)}.
847      */
unregisterSubsystemRestartCallback(ISubsystemRestartCallback callback)848     public boolean unregisterSubsystemRestartCallback(ISubsystemRestartCallback callback) {
849         return mRestartCallbacks.unregister(callback);
850     }
851 
852     /**
853      * Add a listener to get network state change updates.
854      */
addWifiNetworkStateChangedListener(IWifiNetworkStateChangedListener listener)855     public boolean addWifiNetworkStateChangedListener(IWifiNetworkStateChangedListener listener) {
856         return mWifiNetworkStateChangedListeners.register(listener);
857     }
858 
859     /**
860      * Remove a listener for getting network state change updates.
861      */
removeWifiNetworkStateChangedListener( IWifiNetworkStateChangedListener listener)862     public boolean removeWifiNetworkStateChangedListener(
863             IWifiNetworkStateChangedListener listener) {
864         return mWifiNetworkStateChangedListeners.unregister(listener);
865     }
866 
867     /**
868      * Report network state changes to registered listeners.
869      */
onNetworkStateChanged(int cmmRole, int state)870     public void onNetworkStateChanged(int cmmRole, int state) {
871         int numCallbacks = mWifiNetworkStateChangedListeners.beginBroadcast();
872         if (mVerboseLoggingEnabled) {
873             Log.i(TAG, "Sending onWifiNetworkStateChanged cmmRole=" + cmmRole
874                     + " state=" + state);
875         }
876         for (int i = 0; i < numCallbacks; i++) {
877             try {
878                 mWifiNetworkStateChangedListeners.getBroadcastItem(i)
879                         .onWifiNetworkStateChanged(cmmRole, state);
880             } catch (RemoteException e) {
881                 Log.e(TAG, "Failure calling onWifiNetworkStateChanged" + e);
882             }
883         }
884         mWifiNetworkStateChangedListeners.finishBroadcast();
885     }
886 
887     /** Wifi has been toggled. */
888     @Keep
wifiToggled(WorkSource requestorWs)889     public void wifiToggled(WorkSource requestorWs) {
890         mWifiController.sendMessage(WifiController.CMD_WIFI_TOGGLED, requestorWs);
891     }
892 
893     /** Airplane Mode has been toggled. */
airplaneModeToggled()894     public void airplaneModeToggled() {
895         mWifiController.sendMessage(WifiController.CMD_AIRPLANE_TOGGLED);
896     }
897 
898     /** Starts SoftAp. */
startSoftAp(SoftApModeConfiguration softApConfig, WorkSource requestorWs)899     public void startSoftAp(SoftApModeConfiguration softApConfig, WorkSource requestorWs) {
900         mWifiController.sendMessage(WifiController.CMD_SET_AP, 1, 0,
901                 Pair.create(softApConfig, requestorWs));
902     }
903 
904     /** Stop SoftAp. */
stopSoftAp(int mode)905     public void stopSoftAp(int mode) {
906         mWifiController.sendMessage(WifiController.CMD_SET_AP, 0, mode);
907     }
908 
909     /** Update SoftAp Capability. */
updateSoftApCapability(SoftApCapability capability, int ipMode)910     public void updateSoftApCapability(SoftApCapability capability, int ipMode) {
911         mWifiController.sendMessage(WifiController.CMD_UPDATE_AP_CAPABILITY, ipMode, 0, capability);
912     }
913 
914     /** Update SoftAp Configuration. */
updateSoftApConfiguration(SoftApConfiguration config)915     public void updateSoftApConfiguration(SoftApConfiguration config) {
916         mWifiController.sendMessage(WifiController.CMD_UPDATE_AP_CONFIG, config);
917     }
918 
919     /** Emergency Callback Mode has changed. */
emergencyCallbackModeChanged(boolean isInEmergencyCallbackMode)920     public void emergencyCallbackModeChanged(boolean isInEmergencyCallbackMode) {
921         mWifiController.sendMessage(
922                 WifiController.CMD_EMERGENCY_MODE_CHANGED, isInEmergencyCallbackMode ? 1 : 0);
923     }
924 
925     /** Emergency Call state has changed. */
emergencyCallStateChanged(boolean isInEmergencyCall)926     public void emergencyCallStateChanged(boolean isInEmergencyCall) {
927         mWifiController.sendMessage(
928                 WifiController.CMD_EMERGENCY_CALL_STATE_CHANGED, isInEmergencyCall ? 1 : 0);
929     }
930 
931     /** Scan always mode has changed. */
scanAlwaysModeChanged()932     public void scanAlwaysModeChanged() {
933         mWifiController.sendMessage(
934                 WifiController.CMD_SCAN_ALWAYS_MODE_CHANGED,
935                 // Scan only mode change is not considered a direct user interaction since user
936                 // is not explicitly turning on wifi scanning (side-effect of location toggle).
937                 // So, use the lowest priority internal requestor worksource to ensure that this
938                 // is treated with the lowest priority.
939                 INTERNAL_REQUESTOR_WS);
940     }
941 
942     /** emergency scan progress indication. */
setEmergencyScanRequestInProgress(boolean inProgress)943     public void setEmergencyScanRequestInProgress(boolean inProgress) {
944         mWifiController.sendMessage(
945                 WifiController.CMD_EMERGENCY_SCAN_STATE_CHANGED,
946                 inProgress ? 1 : 0, 0,
947                 // Emergency scans should have the highest priority, so use settings worksource.
948                 mFacade.getSettingsWorkSource(mContext));
949     }
950 
951     /**
952      * Listener to request a ModeManager instance for a particular operation.
953      */
954     public interface ExternalClientModeManagerRequestListener {
955         /**
956          * Returns an instance of ClientModeManager or null if the request failed (when wifi is
957          * off).
958          */
onAnswer(@ullable ClientModeManager modeManager)959         void onAnswer(@Nullable ClientModeManager modeManager);
960     }
961 
962     private static class AdditionalClientModeManagerRequestInfo {
963         @NonNull public final ExternalClientModeManagerRequestListener listener;
964         @NonNull public final WorkSource requestorWs;
965         @NonNull public final ClientConnectivityRole clientRole;
966         @NonNull public final String ssid;
967         @Nullable public final String bssid;
968         public final boolean didUserApprove;
969         public boolean preferSecondarySta = false;
970 
AdditionalClientModeManagerRequestInfo( @onNull ExternalClientModeManagerRequestListener listener, @NonNull WorkSource requestorWs, @NonNull ClientConnectivityRole clientRole, @NonNull String ssid, @Nullable String bssid, boolean didUserApprove)971         AdditionalClientModeManagerRequestInfo(
972                 @NonNull ExternalClientModeManagerRequestListener listener,
973                 @NonNull WorkSource requestorWs,
974                 @NonNull ClientConnectivityRole clientRole,
975                 @NonNull String ssid,
976                 // For some use-cases, bssid is selected by firmware.
977                 @Nullable String bssid,
978                 boolean didUserApprove) {
979             this.listener = listener;
980             this.requestorWs = requestorWs;
981             this.clientRole = clientRole;
982             this.ssid = ssid;
983             this.bssid = bssid;
984             this.didUserApprove = didUserApprove;
985         }
986     }
987 
988     /**
989      * Request a local only client manager.
990      * @param listener used to receive the requested ClientModeManager. Will receive:
991      *                 1. null - if Wifi is toggled off
992      *                 2. The primary ClientModeManager - if a new ClientModeManager cannot be
993      *                    created.
994      *                 3. The new ClientModeManager - if it was created successfully.
995      * @param requestorWs the WorkSource for this request
996      * @param didUserApprove if user explicitly approve on this request
997      * @param preferSecondarySta prefer to use secondary CMM for this request if possible
998      */
requestLocalOnlyClientModeManager( @onNull ExternalClientModeManagerRequestListener listener, @NonNull WorkSource requestorWs, @NonNull String ssid, @NonNull String bssid, boolean didUserApprove, boolean preferSecondarySta)999     public void requestLocalOnlyClientModeManager(
1000             @NonNull ExternalClientModeManagerRequestListener listener,
1001             @NonNull WorkSource requestorWs, @NonNull String ssid, @NonNull String bssid,
1002             boolean didUserApprove, boolean preferSecondarySta) {
1003         if (listener == null) {
1004             Log.wtf(TAG, "Cannot provide a null ExternalClientModeManagerRequestListener");
1005             return;
1006         }
1007         if (requestorWs == null) {
1008             Log.wtf(TAG, "Cannot provide a null WorkSource");
1009             return;
1010         }
1011 
1012         AdditionalClientModeManagerRequestInfo additionalClientModeManagerRequestInfo =
1013                 new AdditionalClientModeManagerRequestInfo(listener, requestorWs,
1014                         ROLE_CLIENT_LOCAL_ONLY, ssid, bssid, didUserApprove);
1015         additionalClientModeManagerRequestInfo.preferSecondarySta = preferSecondarySta;
1016 
1017         mWifiController.sendMessage(
1018                 WifiController.CMD_REQUEST_ADDITIONAL_CLIENT_MODE_MANAGER,
1019                 additionalClientModeManagerRequestInfo);
1020     }
1021 
1022     /**
1023      * Request a secondary long lived client manager.
1024      *
1025      * @param listener used to receive the requested ClientModeManager. Will receive:
1026      *                 1. null - if Wifi is toggled off
1027      *                 2. The primary ClientModeManager - if a new ClientModeManager cannot be
1028      *                    created.
1029      *                 3. The new ClientModeManager - if it was created successfully.
1030      * @param requestorWs the WorkSource for this request
1031      */
requestSecondaryLongLivedClientModeManager( @onNull ExternalClientModeManagerRequestListener listener, @NonNull WorkSource requestorWs, @NonNull String ssid, @Nullable String bssid)1032     public void requestSecondaryLongLivedClientModeManager(
1033             @NonNull ExternalClientModeManagerRequestListener listener,
1034             @NonNull WorkSource requestorWs, @NonNull String ssid, @Nullable String bssid) {
1035         if (listener == null) {
1036             Log.wtf(TAG, "Cannot provide a null ExternalClientModeManagerRequestListener");
1037             return;
1038         }
1039         if (requestorWs == null) {
1040             Log.wtf(TAG, "Cannot provide a null WorkSource");
1041             return;
1042         }
1043         mWifiController.sendMessage(
1044                 WifiController.CMD_REQUEST_ADDITIONAL_CLIENT_MODE_MANAGER,
1045                 new AdditionalClientModeManagerRequestInfo(listener, requestorWs,
1046                         ROLE_CLIENT_SECONDARY_LONG_LIVED, ssid, bssid, false));
1047     }
1048 
1049     /**
1050      * Request a secondary transient client manager.
1051      *
1052      * @param listener used to receive the requested ClientModeManager. Will receive:
1053      *                 1. null - if Wifi is toggled off.
1054      *                 2. An existing secondary transient ClientModeManager - if it already exists.
1055      *                 3. A new secondary transient ClientModeManager - if one doesn't exist and one
1056      *                    was created successfully.
1057      *                 4. The primary ClientModeManager - if a new ClientModeManager cannot be
1058      *                    created.
1059      * @param requestorWs the WorkSource for this request
1060      */
requestSecondaryTransientClientModeManager( @onNull ExternalClientModeManagerRequestListener listener, @NonNull WorkSource requestorWs, @NonNull String ssid, @Nullable String bssid)1061     public void requestSecondaryTransientClientModeManager(
1062             @NonNull ExternalClientModeManagerRequestListener listener,
1063             @NonNull WorkSource requestorWs, @NonNull String ssid, @Nullable String bssid) {
1064         if (listener == null) {
1065             Log.wtf(TAG, "Cannot provide a null ExternalClientModeManagerRequestListener");
1066             return;
1067         }
1068         if (requestorWs == null) {
1069             Log.wtf(TAG, "Cannot provide a null WorkSource");
1070             return;
1071         }
1072         mWifiController.sendMessage(
1073                 WifiController.CMD_REQUEST_ADDITIONAL_CLIENT_MODE_MANAGER,
1074                 new AdditionalClientModeManagerRequestInfo(listener, requestorWs,
1075                         ROLE_CLIENT_SECONDARY_TRANSIENT, ssid, bssid, false));
1076     }
1077 
1078     /**
1079      * Checks if a CMM can be started for MBB.
1080      */
canRequestSecondaryTransientClientModeManager()1081     public boolean canRequestSecondaryTransientClientModeManager() {
1082         return canRequestMoreClientModeManagersInRole(INTERNAL_REQUESTOR_WS,
1083                 ROLE_CLIENT_SECONDARY_TRANSIENT, false);
1084     }
1085 
1086     /**
1087      * Remove the provided client manager.
1088      */
removeClientModeManager(ClientModeManager clientModeManager)1089     public void removeClientModeManager(ClientModeManager clientModeManager) {
1090         mWifiController.sendMessage(
1091                 WifiController.CMD_REMOVE_ADDITIONAL_CLIENT_MODE_MANAGER, clientModeManager);
1092     }
1093 
1094     /**
1095      * Check whether we have a primary client mode manager (indicates wifi toggle on).
1096      */
hasPrimaryClientModeManager()1097     public boolean hasPrimaryClientModeManager() {
1098         return getClientModeManagerInRole(ROLE_CLIENT_PRIMARY) != null;
1099     }
1100 
1101     /**
1102      * Checks whether there exists a primary or scan only mode manager.
1103      * @return
1104      */
hasPrimaryOrScanOnlyModeManager()1105     private boolean hasPrimaryOrScanOnlyModeManager() {
1106         return getClientModeManagerInRole(ROLE_CLIENT_PRIMARY) != null
1107                 || getClientModeManagerInRole(ROLE_CLIENT_SCAN_ONLY) != null
1108                 || getClientModeManagerTransitioningIntoRole(ROLE_CLIENT_PRIMARY) != null
1109                 || getClientModeManagerTransitioningIntoRole(ROLE_CLIENT_SCAN_ONLY) != null;
1110     }
1111 
1112     /**
1113      * Returns primary client mode manager if any, else returns null
1114      * This mode manager can be the default route on the device & will handle all external API
1115      * calls.
1116      * @return Instance of {@link ConcreteClientModeManager} or null.
1117      */
1118     @Keep
1119     @Nullable
getPrimaryClientModeManagerNullable()1120     public ConcreteClientModeManager getPrimaryClientModeManagerNullable() {
1121         return getClientModeManagerInRole(ROLE_CLIENT_PRIMARY);
1122     }
1123 
1124     /**
1125      * Returns primary client mode manager if any, else returns an instance of
1126      * {@link ClientModeManager}.
1127      * This mode manager can be the default route on the device & will handle all external API
1128      * calls.
1129      * @return Instance of {@link ClientModeManager}.
1130      */
1131     @Keep
1132     @NonNull
getPrimaryClientModeManager()1133     public ClientModeManager getPrimaryClientModeManager() {
1134         ClientModeManager cm = getPrimaryClientModeManagerNullable();
1135         if (cm != null) return cm;
1136         // If there is no primary client manager, return the default one.
1137         return mDefaultClientModeManager;
1138     }
1139 
1140     /**
1141      * Returns all instances of ClientModeManager in
1142      * {@link ActiveModeManager.ClientInternetConnectivityRole} roles.
1143      * @return List of {@link ClientModeManager}.
1144      */
1145     @NonNull
getInternetConnectivityClientModeManagers()1146     public List<ClientModeManager> getInternetConnectivityClientModeManagers() {
1147         List<ClientModeManager> modeManagers = new ArrayList<>();
1148         for (ConcreteClientModeManager manager : mClientModeManagers) {
1149             if (manager.getRole() instanceof ClientInternetConnectivityRole) {
1150                 modeManagers.add(manager);
1151             }
1152         }
1153         return modeManagers;
1154     }
1155 
1156     /** Stop all secondary transient ClientModeManagers. */
stopAllClientModeManagersInRole(ClientRole role)1157     public void stopAllClientModeManagersInRole(ClientRole role) {
1158         // there should only be at most one Make Before Break CMM, but check all of them to be safe.
1159         for (ConcreteClientModeManager manager : mClientModeManagers) {
1160             if (manager.getRole() == role) {
1161                 stopAdditionalClientModeManager(manager);
1162             }
1163         }
1164     }
1165 
1166     @NonNull
1167     @Keep
getClientModeManagers()1168     public List<ClientModeManager> getClientModeManagers() {
1169         return new ArrayList<>(mClientModeManagers);
1170     }
1171 
1172     /**
1173      * Returns scan only client mode manager, if any.
1174      * This mode manager will only allow scanning.
1175      * @return Instance of {@link ClientModeManager} or null if none present.
1176      */
1177     @Nullable
getScanOnlyClientModeManager()1178     public ClientModeManager getScanOnlyClientModeManager() {
1179         return getClientModeManagerInRole(ROLE_CLIENT_SCAN_ONLY);
1180     }
1181 
1182     /**
1183      * Returns tethered softap manager, if any.
1184      * @return Instance of {@link SoftApManager} or null if none present.
1185      */
1186     @Nullable
getTetheredSoftApManager()1187     public SoftApManager getTetheredSoftApManager() {
1188         return getSoftApManagerInRole(ROLE_SOFTAP_TETHERED);
1189     }
1190 
1191     /**
1192      * Returns LOHS softap manager, if any.
1193      * @return Instance of {@link SoftApManager} or null if none present.
1194      */
1195     @Nullable
getLocalOnlySoftApManager()1196     public SoftApManager getLocalOnlySoftApManager() {
1197         return getSoftApManagerInRole(ActiveModeManager.ROLE_SOFTAP_LOCAL_ONLY);
1198     }
1199 
hasAnyModeManager()1200     private boolean hasAnyModeManager() {
1201         return !mClientModeManagers.isEmpty() || !mSoftApManagers.isEmpty();
1202     }
1203 
hasAnyClientModeManager()1204     private boolean hasAnyClientModeManager() {
1205         return !mClientModeManagers.isEmpty();
1206     }
1207 
hasAnyClientModeManagerInConnectivityRole()1208     private boolean hasAnyClientModeManagerInConnectivityRole() {
1209         for (ConcreteClientModeManager manager : mClientModeManagers) {
1210             if (manager.getRole() instanceof ClientConnectivityRole) return true;
1211         }
1212         return false;
1213     }
1214 
hasAnySoftApManager()1215     private boolean hasAnySoftApManager() {
1216         return !mSoftApManagers.isEmpty();
1217     }
1218 
1219     /**
1220      * @return true if all the client mode managers are in scan only role,
1221      * false if there are no client mode managers present or if any of them are not in scan only
1222      * role.
1223      */
areAllClientModeManagersInScanOnlyRole()1224     private boolean areAllClientModeManagersInScanOnlyRole() {
1225         if (mClientModeManagers.isEmpty()) return false;
1226         for (ConcreteClientModeManager manager : mClientModeManagers) {
1227             if (manager.getRole() != ROLE_CLIENT_SCAN_ONLY) return false;
1228         }
1229         return true;
1230     }
1231 
1232     /** Get any client mode manager in the given role, or null if none was found. */
1233     @Keep
1234     @Nullable
getClientModeManagerInRole(ClientRole role)1235     public ConcreteClientModeManager getClientModeManagerInRole(ClientRole role) {
1236         for (ConcreteClientModeManager manager : mClientModeManagers) {
1237             if (manager.getRole() == role) return manager;
1238         }
1239         return null;
1240     }
1241 
1242     /** Get any client mode manager in the given target role, or null if none was found. */
1243     @Nullable
getClientModeManagerTransitioningIntoRole(ClientRole role)1244     public ConcreteClientModeManager getClientModeManagerTransitioningIntoRole(ClientRole role) {
1245         for (ConcreteClientModeManager manager : mClientModeManagers) {
1246             if (manager.getTargetRole() == role) return manager;
1247         }
1248         return null;
1249     }
1250 
1251     /** Get all client mode managers in the specified roles. */
1252     @NonNull
getClientModeManagersInRoles(ClientRole... roles)1253     public List<ConcreteClientModeManager> getClientModeManagersInRoles(ClientRole... roles) {
1254         Set<ClientRole> rolesSet = Set.of(roles);
1255         List<ConcreteClientModeManager> result = new ArrayList<>();
1256         for (ConcreteClientModeManager manager : mClientModeManagers) {
1257             ClientRole role = manager.getRole();
1258             if (role != null && rolesSet.contains(role)) {
1259                 result.add(manager);
1260             }
1261         }
1262         return result;
1263     }
1264 
1265     @Nullable
getSoftApManagerInRole(SoftApRole role)1266     private SoftApManager getSoftApManagerInRole(SoftApRole role) {
1267         for (SoftApManager manager : mSoftApManagers) {
1268             if (manager.getRole() == role) return manager;
1269         }
1270         return null;
1271     }
1272 
getRoleForSoftApIpMode(int ipMode)1273     private SoftApRole getRoleForSoftApIpMode(int ipMode) {
1274         return ipMode == IFACE_IP_MODE_TETHERED
1275                 ? ROLE_SOFTAP_TETHERED
1276                 : ActiveModeManager.ROLE_SOFTAP_LOCAL_ONLY;
1277     }
1278 
1279     /**
1280      * Method to enable soft ap for wifi hotspot.
1281      *
1282      * The supplied SoftApModeConfiguration includes the target softap WifiConfiguration (or null if
1283      * the persisted config is to be used) and the target operating mode (ex,
1284      * {@link WifiManager#IFACE_IP_MODE_TETHERED} {@link WifiManager#IFACE_IP_MODE_LOCAL_ONLY}).
1285      *
1286      * @param softApConfig SoftApModeConfiguration for the hostapd softap
1287      */
startSoftApModeManager( @onNull SoftApModeConfiguration softApConfig, @NonNull WorkSource requestorWs)1288     private void startSoftApModeManager(
1289             @NonNull SoftApModeConfiguration softApConfig, @NonNull WorkSource requestorWs) {
1290         Log.d(TAG, "Starting SoftApModeManager config = " + softApConfig.getSoftApConfiguration());
1291         Preconditions.checkState(softApConfig.getTargetMode() == IFACE_IP_MODE_LOCAL_ONLY
1292                 || softApConfig.getTargetMode() == IFACE_IP_MODE_TETHERED);
1293 
1294         WifiServiceImpl.SoftApCallbackInternal callback =
1295                 softApConfig.getTargetMode() == IFACE_IP_MODE_LOCAL_ONLY
1296                         ? mLohsCallback : mSoftApCallback;
1297         SoftApManager manager = mWifiInjector.makeSoftApManager(
1298                 new SoftApListener(), callback, softApConfig, requestorWs,
1299                 getRoleForSoftApIpMode(softApConfig.getTargetMode()), mVerboseLoggingEnabled);
1300         mSoftApManagers.add(manager);
1301     }
1302 
1303     /**
1304      * Method to stop all soft ap for the specified mode.
1305      *
1306      * This method will stop any active softAp mode managers.
1307      *
1308      * @param ipMode the operating mode of APs to bring down (ex,
1309      *             {@link WifiManager#IFACE_IP_MODE_TETHERED} or
1310      *             {@link WifiManager#IFACE_IP_MODE_LOCAL_ONLY}).
1311      *             Use {@link WifiManager#IFACE_IP_MODE_UNSPECIFIED} to stop all APs.
1312      */
stopSoftApModeManagers(int ipMode)1313     private void stopSoftApModeManagers(int ipMode) {
1314         Log.d(TAG, "Shutting down all softap mode managers in mode " + ipMode);
1315         for (SoftApManager softApManager : mSoftApManagers) {
1316             if (ipMode == WifiManager.IFACE_IP_MODE_UNSPECIFIED
1317                     || getRoleForSoftApIpMode(ipMode) == softApManager.getRole()) {
1318                 softApManager.stop();
1319             }
1320         }
1321     }
1322 
updateCapabilityToSoftApModeManager(SoftApCapability capability, int ipMode)1323     private void updateCapabilityToSoftApModeManager(SoftApCapability capability, int ipMode) {
1324         for (SoftApManager softApManager : mSoftApManagers) {
1325             if (ipMode == softApManager.getSoftApModeConfiguration().getTargetMode()) {
1326                 softApManager.updateCapability(capability);
1327             }
1328         }
1329     }
1330 
updateConfigurationToSoftApModeManager(SoftApConfiguration config)1331     private void updateConfigurationToSoftApModeManager(SoftApConfiguration config) {
1332         for (SoftApManager softApManager : mSoftApManagers) {
1333             softApManager.updateConfiguration(config);
1334         }
1335     }
1336 
1337     /**
1338      * Method to enable a new primary client mode manager in scan only mode.
1339      */
startScanOnlyClientModeManager(WorkSource requestorWs)1340     private boolean startScanOnlyClientModeManager(WorkSource requestorWs) {
1341         if (hasPrimaryOrScanOnlyModeManager()) {
1342             Log.e(TAG, "Unexpected state - scan only CMM should not be started when a primary "
1343                     + "or scan only CMM is already present.");
1344             if (!mIsMultiplePrimaryBugreportTaken) {
1345                 mIsMultiplePrimaryBugreportTaken = true;
1346                 mWifiDiagnostics.takeBugReport("Wi-Fi ActiveModeWarden bugreport",
1347                         "Trying to start scan only mode manager when one already exists.");
1348             }
1349             return false;
1350         }
1351         Log.d(TAG, "Starting primary ClientModeManager in scan only mode");
1352         ConcreteClientModeManager manager = mWifiInjector.makeClientModeManager(
1353                 new ClientListener(), requestorWs, ROLE_CLIENT_SCAN_ONLY, mVerboseLoggingEnabled);
1354         mClientModeManagers.add(manager);
1355         mLastScanOnlyClientModeManagerRequestorWs = requestorWs;
1356         return true;
1357     }
1358 
1359     /**
1360      * Method to enable a new primary client mode manager in connect mode.
1361      */
startPrimaryClientModeManager(WorkSource requestorWs)1362     private boolean startPrimaryClientModeManager(WorkSource requestorWs) {
1363         if (hasPrimaryOrScanOnlyModeManager()) {
1364             Log.e(TAG, "Unexpected state - primary CMM should not be started when a primary "
1365                     + "or scan only CMM is already present.");
1366             if (!mIsMultiplePrimaryBugreportTaken) {
1367                 mIsMultiplePrimaryBugreportTaken = true;
1368                 mWifiDiagnostics.takeBugReport("Wi-Fi ActiveModeWarden bugreport",
1369                         "Trying to start primary mode manager when one already exists.");
1370             }
1371             return false;
1372         }
1373         Log.d(TAG, "Starting primary ClientModeManager in connect mode");
1374         ConcreteClientModeManager manager = mWifiInjector.makeClientModeManager(
1375                 new ClientListener(), requestorWs, ROLE_CLIENT_PRIMARY, mVerboseLoggingEnabled);
1376         mClientModeManagers.add(manager);
1377         mLastPrimaryClientModeManagerRequestorWs = requestorWs;
1378         return true;
1379     }
1380 
1381     /**
1382      * Method to enable a new primary client mode manager.
1383      */
startPrimaryOrScanOnlyClientModeManager(WorkSource requestorWs)1384     private boolean startPrimaryOrScanOnlyClientModeManager(WorkSource requestorWs) {
1385         ActiveModeManager.ClientRole role = getRoleForPrimaryOrScanOnlyClientModeManager();
1386         if (role == ROLE_CLIENT_PRIMARY) {
1387             return startPrimaryClientModeManager(requestorWs);
1388         } else if (role == ROLE_CLIENT_SCAN_ONLY) {
1389             return startScanOnlyClientModeManager(requestorWs);
1390         } else {
1391             return false;
1392         }
1393     }
1394 
getClientModeManagersPrimaryLast()1395     private List<ConcreteClientModeManager> getClientModeManagersPrimaryLast() {
1396         List<ConcreteClientModeManager> primaries = new ArrayList<>();
1397         List<ConcreteClientModeManager> others = new ArrayList<>();
1398         for (ConcreteClientModeManager clientModeManager : mClientModeManagers) {
1399             if (clientModeManager.getRole() == ROLE_CLIENT_PRIMARY) {
1400                 primaries.add(clientModeManager);
1401             } else {
1402                 others.add(clientModeManager);
1403             }
1404         }
1405         if (primaries.size() > 1) {
1406             Log.wtf(TAG, "More than 1 primary CMM detected when turning off Wi-Fi");
1407             mWifiDiagnostics.takeBugReport("Wi-Fi ActiveModeWarden bugreport",
1408                     "Multiple primary CMMs detected when turning off Wi-Fi.");
1409         }
1410         List<ConcreteClientModeManager> result = new ArrayList<>();
1411         result.addAll(others);
1412         result.addAll(primaries);
1413         return result;
1414     }
1415 
1416     /**
1417      * Method to stop all client mode mangers.
1418      */
stopAllClientModeManagers()1419     private void stopAllClientModeManagers() {
1420         Log.d(TAG, "Shutting down all client mode managers");
1421         for (ConcreteClientModeManager clientModeManager : getClientModeManagersPrimaryLast()) {
1422             if (clientModeManager.getRole() == ROLE_CLIENT_PRIMARY) {
1423                 setWifiStateForApiCalls(WIFI_STATE_DISABLING);
1424             }
1425             clientModeManager.stop();
1426         }
1427     }
1428 
1429     /**
1430      * Method to switch all primary client mode manager mode of operation to ScanOnly mode.
1431      */
switchAllPrimaryClientModeManagersToScanOnlyMode(@onNull WorkSource requestorWs)1432     private void switchAllPrimaryClientModeManagersToScanOnlyMode(@NonNull WorkSource requestorWs) {
1433         Log.d(TAG, "Switching all primary client mode managers to scan only mode");
1434         for (ConcreteClientModeManager clientModeManager : mClientModeManagers) {
1435             if (clientModeManager.getRole() != ROLE_CLIENT_PRIMARY) {
1436                 continue;
1437             }
1438             clientModeManager.setRole(ROLE_CLIENT_SCAN_ONLY, requestorWs);
1439         }
1440     }
1441 
stopSecondaryClientModeManagers()1442     private void stopSecondaryClientModeManagers() {
1443         stopAllClientModeManagersInRole(ROLE_CLIENT_LOCAL_ONLY);
1444         stopAllClientModeManagersInRole(ROLE_CLIENT_SECONDARY_TRANSIENT);
1445         stopAllClientModeManagersInRole(ROLE_CLIENT_SECONDARY_LONG_LIVED);
1446     }
1447 
1448     /**
1449      * Method to switch all client mode manager mode of operation (from ScanOnly To Connect &
1450      * vice-versa) based on the toggle state.
1451      */
switchAllPrimaryOrScanOnlyClientModeManagers()1452     private boolean switchAllPrimaryOrScanOnlyClientModeManagers() {
1453         Log.d(TAG, "Switching all client mode managers");
1454         for (ConcreteClientModeManager clientModeManager : mClientModeManagers) {
1455             if (clientModeManager.getRole() != ROLE_CLIENT_PRIMARY
1456                     && clientModeManager.getRole() != ROLE_CLIENT_SCAN_ONLY
1457                     && clientModeManager.getTargetRole() != ROLE_CLIENT_PRIMARY
1458                     && clientModeManager.getTargetRole() != ROLE_CLIENT_SCAN_ONLY) {
1459                 continue;
1460             }
1461             if (!switchPrimaryOrScanOnlyClientModeManagerRole(clientModeManager)) {
1462                 return false;
1463             }
1464         }
1465         return true;
1466     }
1467 
getRoleForPrimaryOrScanOnlyClientModeManager()1468     private ActiveModeManager.ClientRole getRoleForPrimaryOrScanOnlyClientModeManager() {
1469         if (mSettingsStore.isWifiToggleEnabled()) {
1470             return ROLE_CLIENT_PRIMARY;
1471         } else if (mWifiController.shouldEnableScanOnlyMode()) {
1472             return ROLE_CLIENT_SCAN_ONLY;
1473         } else {
1474             Log.e(TAG, "Something is wrong, no client mode toggles enabled");
1475             return null;
1476         }
1477     }
1478 
1479     /**
1480      * Method to switch a client mode manager mode of operation (from ScanOnly To Connect &
1481      * vice-versa) based on the toggle state.
1482      */
switchPrimaryOrScanOnlyClientModeManagerRole( @onNull ConcreteClientModeManager modeManager)1483     private boolean switchPrimaryOrScanOnlyClientModeManagerRole(
1484             @NonNull ConcreteClientModeManager modeManager) {
1485         ActiveModeManager.ClientRole role = getRoleForPrimaryOrScanOnlyClientModeManager();
1486         final WorkSource lastRequestorWs;
1487         if (role == ROLE_CLIENT_PRIMARY) {
1488             lastRequestorWs = mLastPrimaryClientModeManagerRequestorWs;
1489         } else if (role == ROLE_CLIENT_SCAN_ONLY) {
1490             lastRequestorWs = mLastScanOnlyClientModeManagerRequestorWs;
1491         } else {
1492             return false;
1493         }
1494         modeManager.setRole(role, lastRequestorWs);
1495         return true;
1496     }
1497 
1498     /**
1499      * Method to start a new client mode manager.
1500      */
startAdditionalClientModeManager( ClientConnectivityRole role, @NonNull ExternalClientModeManagerRequestListener externalRequestListener, @NonNull WorkSource requestorWs)1501     private boolean startAdditionalClientModeManager(
1502             ClientConnectivityRole role,
1503             @NonNull ExternalClientModeManagerRequestListener externalRequestListener,
1504             @NonNull WorkSource requestorWs) {
1505         Log.d(TAG, "Starting additional ClientModeManager in role: " + role);
1506         ClientListener listener = new ClientListener(externalRequestListener);
1507         ConcreteClientModeManager manager = mWifiInjector.makeClientModeManager(
1508                 listener, requestorWs, role, mVerboseLoggingEnabled);
1509         mClientModeManagers.add(manager);
1510         if (ROLE_CLIENT_SECONDARY_LONG_LIVED.equals(role) || ROLE_CLIENT_LOCAL_ONLY.equals(role)) {
1511             synchronized (mServiceApiLock) {
1512                 mRequestWs.add(new WorkSource(requestorWs));
1513             }
1514         }
1515         return true;
1516     }
1517 
1518     /**
1519      * Method to switch role for an existing non-primary client mode manager.
1520      */
switchRoleForAdditionalClientModeManager( @onNull ConcreteClientModeManager manager, @NonNull ClientConnectivityRole role, @NonNull ExternalClientModeManagerRequestListener externalRequestListener, @NonNull WorkSource requestorWs)1521     private boolean switchRoleForAdditionalClientModeManager(
1522             @NonNull ConcreteClientModeManager manager,
1523             @NonNull ClientConnectivityRole role,
1524             @NonNull ExternalClientModeManagerRequestListener externalRequestListener,
1525             @NonNull WorkSource requestorWs) {
1526         Log.d(TAG, "Switching role for additional ClientModeManager to role: " + role);
1527         ClientListener listener = new ClientListener(externalRequestListener);
1528         synchronized (mServiceApiLock) {
1529             mRequestWs.remove(manager.getRequestorWs());
1530         }
1531         if (ROLE_CLIENT_SECONDARY_LONG_LIVED.equals(role) || ROLE_CLIENT_LOCAL_ONLY.equals(role)) {
1532             synchronized (mServiceApiLock) {
1533                 mRequestWs.add(new WorkSource(requestorWs));
1534             }
1535         }
1536         manager.setRole(role, requestorWs, listener);
1537         return true;
1538     }
1539 
1540     /**
1541      * Method to stop client mode manager.
1542      */
stopAdditionalClientModeManager(ClientModeManager clientModeManager)1543     private void stopAdditionalClientModeManager(ClientModeManager clientModeManager) {
1544         if (clientModeManager instanceof DefaultClientModeManager
1545                 || clientModeManager.getRole() == ROLE_CLIENT_PRIMARY
1546                 || clientModeManager.getRole() == ROLE_CLIENT_SCAN_ONLY) return;
1547         Log.d(TAG, "Shutting down additional client mode manager: " + clientModeManager);
1548         clientModeManager.stop();
1549     }
1550 
1551     /**
1552      * Method to stop all active modes, for example, when toggling airplane mode.
1553      */
shutdownWifi()1554     private void shutdownWifi() {
1555         Log.d(TAG, "Shutting down all mode managers");
1556         for (ActiveModeManager manager : getActiveModeManagers()) {
1557             if (manager.getRole() == ROLE_CLIENT_PRIMARY) {
1558                 setWifiStateForApiCalls(WIFI_STATE_DISABLING);
1559             }
1560             manager.stop();
1561         }
1562     }
1563 
1564     /**
1565      * Dump current state for active mode managers.
1566      *
1567      * Must be called from the main Wifi thread.
1568      */
dump(FileDescriptor fd, PrintWriter pw, String[] args)1569     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1570         pw.println("Dump of " + TAG);
1571         pw.println("Current wifi mode: " + getCurrentMode());
1572         pw.println("Wi-Fi is " + getWifiStateName());
1573         pw.println("NumActiveModeManagers: " + getActiveModeManagerCount());
1574         pw.println("mIsMultiplePrimaryBugreportTaken: " + mIsMultiplePrimaryBugreportTaken);
1575         mWifiController.dump(fd, pw, args);
1576         for (ActiveModeManager manager : getActiveModeManagers()) {
1577             manager.dump(fd, pw, args);
1578         }
1579         mGraveyard.dump(fd, pw, args);
1580         boolean isStaStaConcurrencySupported = mWifiNative.isStaStaConcurrencySupported();
1581         pw.println("STA + STA Concurrency Supported: " + isStaStaConcurrencySupported);
1582         if (isStaStaConcurrencySupported) {
1583             pw.println("   MBB use-case enabled: "
1584                     + mResourceCache.getBoolean(
1585                             R.bool.config_wifiMultiStaNetworkSwitchingMakeBeforeBreakEnabled));
1586             pw.println("   Local only use-case enabled: "
1587                     + mResourceCache.getBoolean(
1588                             R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled));
1589             pw.println("   Restricted use-case enabled: "
1590                     + mResourceCache.getBoolean(
1591                             R.bool.config_wifiMultiStaRestrictedConcurrencyEnabled));
1592             pw.println("   Multi internet use-case enabled: "
1593                     + mResourceCache.getBoolean(
1594                             R.bool.config_wifiMultiStaMultiInternetConcurrencyEnabled));
1595         }
1596         pw.println("STA + AP Concurrency Supported: " + mWifiNative.isStaApConcurrencySupported());
1597         mWifiInjector.getHalDeviceManager().dump(fd, pw, args);
1598         pw.println("Wifi handler thread overruns");
1599         mWifiInjector.getWifiHandlerLocalLog().dump(fd, pw, args);
1600     }
1601 
1602     @VisibleForTesting
getCurrentMode()1603     String getCurrentMode() {
1604         IState state = mWifiController.getCurrentState();
1605         return state == null ? STATE_MACHINE_EXITED_STATE_NAME : state.getName();
1606     }
1607 
1608     @VisibleForTesting
getActiveModeManagers()1609     Collection<ActiveModeManager> getActiveModeManagers() {
1610         ArrayList<ActiveModeManager> activeModeManagers = new ArrayList<>();
1611         activeModeManagers.addAll(mSoftApManagers);
1612         activeModeManagers.addAll(getClientModeManagersPrimaryLast());
1613         return activeModeManagers;
1614     }
1615 
getActiveModeManagerCount()1616     private int getActiveModeManagerCount() {
1617         return mSoftApManagers.size() + mClientModeManagers.size();
1618     }
1619 
1620     @VisibleForTesting
isInEmergencyMode()1621     boolean isInEmergencyMode() {
1622         IState state = mWifiController.getCurrentState();
1623         return ((WifiController.BaseState) state).isInEmergencyMode();
1624     }
1625 
updateBatteryStats()1626     private void updateBatteryStats() {
1627         updateBatteryStatsWifiState(hasAnyModeManager());
1628         if (areAllClientModeManagersInScanOnlyRole()) {
1629             updateBatteryStatsScanModeActive();
1630         }
1631     }
1632 
1633     private class SoftApListener implements ActiveModeManager.Listener<SoftApManager> {
1634         @Override
onStarted(SoftApManager softApManager)1635         public void onStarted(SoftApManager softApManager) {
1636             updateBatteryStats();
1637             invokeOnAddedCallbacks(softApManager);
1638         }
1639 
1640         @Override
onRoleChanged(SoftApManager softApManager)1641         public void onRoleChanged(SoftApManager softApManager) {
1642             Log.w(TAG, "Role switched received on SoftApManager unexpectedly");
1643         }
1644 
1645         @Override
onStopped(SoftApManager softApManager)1646         public void onStopped(SoftApManager softApManager) {
1647             mSoftApManagers.remove(softApManager);
1648             mGraveyard.inter(softApManager);
1649             updateBatteryStats();
1650             mWifiController.sendMessage(WifiController.CMD_AP_STOPPED);
1651             invokeOnRemovedCallbacks(softApManager);
1652         }
1653 
1654         @Override
onStartFailure(SoftApManager softApManager)1655         public void onStartFailure(SoftApManager softApManager) {
1656             mSoftApManagers.remove(softApManager);
1657             mGraveyard.inter(softApManager);
1658             updateBatteryStats();
1659             mWifiController.sendMessage(WifiController.CMD_AP_START_FAILURE);
1660             // onStartFailure can be called when switching between roles. So, remove
1661             // update listeners.
1662             Log.e(TAG, "SoftApManager start failed!" + softApManager);
1663             invokeOnRemovedCallbacks(softApManager);
1664         }
1665     }
1666 
1667     private class ClientListener implements ActiveModeManager.Listener<ConcreteClientModeManager> {
1668         @Nullable
1669         private ExternalClientModeManagerRequestListener mExternalRequestListener; // one shot
1670 
ClientListener()1671         ClientListener() {
1672             this(null);
1673         }
1674 
ClientListener( @ullable ExternalClientModeManagerRequestListener externalRequestListener)1675         ClientListener(
1676                 @Nullable ExternalClientModeManagerRequestListener externalRequestListener) {
1677             mExternalRequestListener = externalRequestListener;
1678         }
1679 
1680         @WifiNative.MultiStaUseCase
getMultiStatUseCase()1681         private int getMultiStatUseCase() {
1682             // Note: The use-case setting finds the first non-primary client mode manager to set
1683             // the use-case to HAL. This does not extend to 3 STA concurrency when there are
1684             // 2 secondary STA client mode managers.
1685             for (ClientModeManager cmm : getClientModeManagers()) {
1686                 ClientRole clientRole = cmm.getRole();
1687                 if (clientRole == ROLE_CLIENT_LOCAL_ONLY
1688                         || clientRole == ROLE_CLIENT_SECONDARY_LONG_LIVED) {
1689                     return WifiNative.DUAL_STA_NON_TRANSIENT_UNBIASED;
1690                 } else if (clientRole == ROLE_CLIENT_SECONDARY_TRANSIENT) {
1691                     return WifiNative.DUAL_STA_TRANSIENT_PREFER_PRIMARY;
1692                 }
1693             }
1694             // if single STA, a safe default is PREFER_PRIMARY
1695             return WifiNative.DUAL_STA_TRANSIENT_PREFER_PRIMARY;
1696         }
1697 
1698         /**
1699          * Hardware needs to be configured for STA + STA before sending the callbacks to clients
1700          * letting them know that CM is ready for use.
1701          */
configureHwForMultiStaIfNecessary()1702         private void configureHwForMultiStaIfNecessary() {
1703             mWifiNative.setMultiStaUseCase(getMultiStatUseCase());
1704             String primaryIfaceName = getPrimaryClientModeManager().getInterfaceName();
1705             // if no primary exists (occurs briefly during Make Before Break), don't update the
1706             // primary and keep the previous primary. Only update WifiNative when the new primary is
1707             // activated.
1708             if (primaryIfaceName != null) {
1709                 mWifiNative.setMultiStaPrimaryConnection(primaryIfaceName);
1710             }
1711         }
1712 
onStartedOrRoleChanged(ConcreteClientModeManager clientModeManager)1713         private void onStartedOrRoleChanged(ConcreteClientModeManager clientModeManager) {
1714             updateClientScanMode();
1715             updateBatteryStats();
1716             configureHwForMultiStaIfNecessary();
1717             if (mExternalRequestListener != null) {
1718                 mExternalRequestListener.onAnswer(clientModeManager);
1719                 mExternalRequestListener = null; // reset after one shot.
1720             }
1721 
1722             // Report to SarManager
1723             reportWifiStateToSarManager();
1724         }
1725 
reportWifiStateToSarManager()1726         private void reportWifiStateToSarManager() {
1727             if (areAllClientModeManagersInScanOnlyRole()) {
1728                 // Inform sar manager that scan only is being enabled
1729                 mWifiInjector.getSarManager().setScanOnlyWifiState(WifiManager.WIFI_STATE_ENABLED);
1730             } else {
1731                 // Inform sar manager that scan only is being disabled
1732                 mWifiInjector.getSarManager().setScanOnlyWifiState(WifiManager.WIFI_STATE_DISABLED);
1733             }
1734             if (hasAnyClientModeManagerInConnectivityRole()) {
1735                 // Inform sar manager that wifi is Enabled
1736                 mWifiInjector.getSarManager().setClientWifiState(WifiManager.WIFI_STATE_ENABLED);
1737             } else {
1738                 // Inform sar manager that wifi is being disabled
1739                 mWifiInjector.getSarManager().setClientWifiState(WifiManager.WIFI_STATE_DISABLED);
1740             }
1741         }
1742 
onPrimaryChangedDueToStartedOrRoleChanged( ConcreteClientModeManager clientModeManager)1743         private void onPrimaryChangedDueToStartedOrRoleChanged(
1744                 ConcreteClientModeManager clientModeManager) {
1745             if (clientModeManager.getRole() != ROLE_CLIENT_PRIMARY
1746                     && clientModeManager == mLastPrimaryClientModeManager) {
1747                 // CMM was primary, but is no longer primary
1748                 invokeOnPrimaryClientModeManagerChangedCallbacks(clientModeManager, null);
1749                 mLastPrimaryClientModeManager = null;
1750             } else if (clientModeManager.getRole() == ROLE_CLIENT_PRIMARY
1751                     && clientModeManager != mLastPrimaryClientModeManager) {
1752                 // CMM is primary, but wasn't primary before
1753                 invokeOnPrimaryClientModeManagerChangedCallbacks(
1754                         mLastPrimaryClientModeManager, clientModeManager);
1755                 mLastPrimaryClientModeManager = clientModeManager;
1756                 setCurrentNetwork(clientModeManager.getCurrentNetwork());
1757             }
1758             setSupportedFeatureSet(
1759                     // If primary doesn't exist, DefaultClientModeManager getInterfaceName name
1760                     // returns null.
1761                     mWifiNative.getSupportedFeatureSet(
1762                             getPrimaryClientModeManager().getInterfaceName()),
1763                     mWifiNative.isStaApConcurrencySupported(),
1764                     mWifiNative.isStaStaConcurrencySupported());
1765             if (clientModeManager.getRole() == ROLE_CLIENT_PRIMARY) {
1766                 int band = mWifiNative.getSupportedBandsForSta(
1767                         clientModeManager.getInterfaceName());
1768                 if (band == WifiScanner.WIFI_BAND_UNSPECIFIED) band = getStaBandsFromConfigStore();
1769                 setBandSupported(band);
1770             }
1771         }
1772 
1773         @Override
onStarted(@onNull ConcreteClientModeManager clientModeManager)1774         public void onStarted(@NonNull ConcreteClientModeManager clientModeManager) {
1775             onStartedOrRoleChanged(clientModeManager);
1776             invokeOnAddedCallbacks(clientModeManager);
1777             // invoke "added" callbacks before primary changed
1778             onPrimaryChangedDueToStartedOrRoleChanged(clientModeManager);
1779         }
1780 
1781         @Override
onRoleChanged(@onNull ConcreteClientModeManager clientModeManager)1782         public void onRoleChanged(@NonNull ConcreteClientModeManager clientModeManager) {
1783             onStartedOrRoleChanged(clientModeManager);
1784             invokeOnRoleChangedCallbacks(clientModeManager);
1785             onPrimaryChangedDueToStartedOrRoleChanged(clientModeManager);
1786         }
1787 
onStoppedOrStartFailure(ConcreteClientModeManager clientModeManager)1788         private void onStoppedOrStartFailure(ConcreteClientModeManager clientModeManager) {
1789             mClientModeManagers.remove(clientModeManager);
1790             if (ROLE_CLIENT_SECONDARY_LONG_LIVED.equals(clientModeManager.getPreviousRole())
1791                     || ROLE_CLIENT_LOCAL_ONLY.equals(clientModeManager.getPreviousRole())) {
1792                 synchronized (mServiceApiLock) {
1793                     mRequestWs.remove(clientModeManager.getRequestorWs());
1794                 }
1795             }
1796             mGraveyard.inter(clientModeManager);
1797             updateClientScanMode();
1798             updateBatteryStats();
1799             if (clientModeManager == mLastPrimaryClientModeManager) {
1800                 // CMM was primary, but was stopped
1801                 invokeOnPrimaryClientModeManagerChangedCallbacks(
1802                         mLastPrimaryClientModeManager, null);
1803                 mLastPrimaryClientModeManager = null;
1804                 setSupportedFeatureSet(mWifiNative.getSupportedFeatureSet(null),
1805                         mWifiNative.isStaApConcurrencySupported(),
1806                         mWifiNative.isStaStaConcurrencySupported());
1807                 setBandSupported(getStaBandsFromConfigStore());
1808             }
1809             // invoke "removed" callbacks after primary changed
1810             invokeOnRemovedCallbacks(clientModeManager);
1811 
1812             // Report to SarManager
1813             reportWifiStateToSarManager();
1814         }
1815 
1816         @Override
onStopped(@onNull ConcreteClientModeManager clientModeManager)1817         public void onStopped(@NonNull ConcreteClientModeManager clientModeManager) {
1818             onStoppedOrStartFailure(clientModeManager);
1819             mWifiController.sendMessage(WifiController.CMD_STA_STOPPED);
1820         }
1821 
1822         @Override
onStartFailure(@onNull ConcreteClientModeManager clientModeManager)1823         public void onStartFailure(@NonNull ConcreteClientModeManager clientModeManager) {
1824             Log.e(TAG, "ClientModeManager start failed!" + clientModeManager);
1825             // onStartFailure can be called when switching between roles. So, remove
1826             // update listeners.
1827             onStoppedOrStartFailure(clientModeManager);
1828             mWifiController.sendMessage(WifiController.CMD_STA_START_FAILURE);
1829         }
1830     }
1831 
1832     // Update the scan state based on all active mode managers.
updateClientScanMode()1833     private void updateClientScanMode() {
1834         boolean scanEnabled = hasAnyClientModeManager();
1835         boolean scanningForHiddenNetworksEnabled;
1836 
1837         if (mResourceCache
1838                 .getBoolean(R.bool.config_wifiScanHiddenNetworksScanOnlyMode)) {
1839             scanningForHiddenNetworksEnabled = hasAnyClientModeManager();
1840         } else {
1841             scanningForHiddenNetworksEnabled = hasAnyClientModeManagerInConnectivityRole();
1842         }
1843         mScanRequestProxy.enableScanning(scanEnabled, scanningForHiddenNetworksEnabled);
1844     }
1845 
1846     /**
1847      *  Helper method to report wifi state as on/off (doesn't matter which mode).
1848      *
1849      *  @param enabled boolean indicating that some mode has been turned on or off
1850      */
updateBatteryStatsWifiState(boolean enabled)1851     private void updateBatteryStatsWifiState(boolean enabled) {
1852         if (enabled) {
1853             if (getActiveModeManagerCount() == 1) {
1854                 // only report wifi on if we haven't already
1855                 mBatteryStatsManager.reportWifiOn();
1856             }
1857         } else {
1858             if (getActiveModeManagerCount() == 0) {
1859                 // only report if we don't have any active modes
1860                 mBatteryStatsManager.reportWifiOff();
1861             }
1862         }
1863     }
1864 
updateBatteryStatsScanModeActive()1865     private void updateBatteryStatsScanModeActive() {
1866         mBatteryStatsManager.reportWifiState(BatteryStatsManager.WIFI_STATE_OFF_SCANNING, null);
1867     }
1868 
1869     /**
1870      * Called to pull metrics from ActiveModeWarden to WifiMetrics when a dump is triggered, as
1871      * opposed to the more common push metrics which are reported to WifiMetrics as soon as they
1872      * occur.
1873      */
updateMetrics()1874     public void updateMetrics() {
1875         mWifiMetrics.setIsMakeBeforeBreakSupported(isStaStaConcurrencySupportedForMbb());
1876     }
1877 
1878     /**
1879      * During Wifi off -> on transition, there is a race condition between country code update,
1880      * single scan triggered by App based ACTION_WIFI_SCAN_AVAILABILITY_CHANGED. The single scan
1881      * might fail if country code is updated while the scan is ongoing.
1882      * To mitigate that issue, send ACTION_WIFI_SCAN_AVAILABILITY_CHANGED again when the country
1883      * code update is completed.
1884      *
1885      * @param newCountryCode the new country code, null when there is no active mode enabled.
1886      */
updateClientScanModeAfterCountryCodeUpdate(@ullable String newCountryCode)1887     public void updateClientScanModeAfterCountryCodeUpdate(@Nullable String newCountryCode) {
1888         // Handle country code changed only during Wifi off -> on transition.
1889         if (newCountryCode != null) {
1890             updateClientScanMode();
1891         }
1892     }
1893 
1894     /**
1895      * WifiController is the class used to manage wifi state for various operating
1896      * modes (normal, airplane, wifi hotspot, etc.).
1897      */
1898     private class WifiController extends StateMachine {
1899         private static final String TAG = "WifiController";
1900 
1901         // Maximum limit to use for timeout delay if the value from overlay setting is too large.
1902         private static final int MAX_RECOVERY_TIMEOUT_DELAY_MS = 4000;
1903 
1904         private static final int BASE = Protocol.BASE_WIFI_CONTROLLER;
1905 
1906         static final int CMD_EMERGENCY_MODE_CHANGED                 = BASE + 1;
1907         static final int CMD_EMERGENCY_SCAN_STATE_CHANGED           = BASE + 2;
1908         static final int CMD_SCAN_ALWAYS_MODE_CHANGED               = BASE + 7;
1909         static final int CMD_WIFI_TOGGLED                           = BASE + 8;
1910         static final int CMD_AIRPLANE_TOGGLED                       = BASE + 9;
1911         static final int CMD_SET_AP                                 = BASE + 10;
1912         static final int CMD_EMERGENCY_CALL_STATE_CHANGED           = BASE + 14;
1913         static final int CMD_AP_STOPPED                             = BASE + 15;
1914         static final int CMD_STA_START_FAILURE                      = BASE + 16;
1915         // Command used to trigger a wifi stack restart when in active mode
1916         static final int CMD_RECOVERY_RESTART_WIFI                  = BASE + 17;
1917         // Internal command used to complete wifi stack restart
1918         private static final int CMD_RECOVERY_RESTART_WIFI_CONTINUE = BASE + 18;
1919         // Command to disable wifi when SelfRecovery is throttled or otherwise not doing full
1920         // recovery
1921         static final int CMD_RECOVERY_DISABLE_WIFI                   = BASE + 19;
1922         static final int CMD_STA_STOPPED                             = BASE + 20;
1923         static final int CMD_DEFERRED_RECOVERY_RESTART_WIFI          = BASE + 22;
1924         static final int CMD_AP_START_FAILURE                        = BASE + 23;
1925         static final int CMD_UPDATE_AP_CAPABILITY                    = BASE + 24;
1926         static final int CMD_UPDATE_AP_CONFIG                        = BASE + 25;
1927         static final int CMD_REQUEST_ADDITIONAL_CLIENT_MODE_MANAGER  = BASE + 26;
1928         static final int CMD_REMOVE_ADDITIONAL_CLIENT_MODE_MANAGER   = BASE + 27;
1929         static final int CMD_SATELLITE_MODE_CHANGED                  = BASE + 28;
1930 
1931         private final EnabledState mEnabledState;
1932         private final DisabledState mDisabledState;
1933 
1934         private boolean mIsInEmergencyCall = false;
1935         private boolean mIsInEmergencyCallbackMode = false;
1936         private boolean mIsEmergencyScanInProgress = false;
1937 
WifiController()1938         WifiController() {
1939             super(TAG, mLooper);
1940             final int threshold = mResourceCache.getInteger(
1941                     R.integer.config_wifiConfigurationWifiRunnerThresholdInMs);
1942             DefaultState defaultState = new DefaultState(threshold);
1943             mEnabledState = new EnabledState(threshold);
1944             mDisabledState = new DisabledState(threshold);
1945             addState(defaultState); {
1946                 addState(mDisabledState, defaultState);
1947                 addState(mEnabledState, defaultState);
1948             }
1949 
1950             setLogRecSize(100);
1951             setLogOnlyTransitions(false);
1952 
1953         }
1954 
1955         /**
1956          * Return the additional string to be logged by LogRec.
1957          *
1958          * @param msg that was processed
1959          * @return information to be logged as a String
1960          */
1961         @Override
getLogRecString(Message msg)1962         protected String getLogRecString(Message msg) {
1963             StringBuilder sb = new StringBuilder();
1964             sb.append(msg.arg1)
1965                     .append(" ").append(msg.arg2)
1966                     .append(" num ClientModeManagers:").append(mClientModeManagers.size())
1967                     .append(" num SoftApManagers:").append(mSoftApManagers.size());
1968             if (msg.obj != null) {
1969                 sb.append(" ").append(msg.obj);
1970             }
1971             return sb.toString();
1972         }
1973 
1974         @Override
getWhatToString(int what)1975         protected String getWhatToString(int what) {
1976             switch (what) {
1977                 case CMD_AIRPLANE_TOGGLED:
1978                     return "CMD_AIRPLANE_TOGGLED";
1979                 case CMD_AP_START_FAILURE:
1980                     return "CMD_AP_START_FAILURE";
1981                 case CMD_AP_STOPPED:
1982                     return "CMD_AP_STOPPED";
1983                 case CMD_DEFERRED_RECOVERY_RESTART_WIFI:
1984                     return "CMD_DEFERRED_RECOVERY_RESTART_WIFI";
1985                 case CMD_EMERGENCY_CALL_STATE_CHANGED:
1986                     return "CMD_EMERGENCY_CALL_STATE_CHANGED";
1987                 case CMD_EMERGENCY_MODE_CHANGED:
1988                     return "CMD_EMERGENCY_MODE_CHANGED";
1989                 case CMD_RECOVERY_DISABLE_WIFI:
1990                     return "CMD_RECOVERY_DISABLE_WIFI";
1991                 case CMD_RECOVERY_RESTART_WIFI:
1992                     return "CMD_RECOVERY_RESTART_WIFI";
1993                 case CMD_RECOVERY_RESTART_WIFI_CONTINUE:
1994                     return "CMD_RECOVERY_RESTART_WIFI_CONTINUE";
1995                 case CMD_REMOVE_ADDITIONAL_CLIENT_MODE_MANAGER:
1996                     return "CMD_REMOVE_ADDITIONAL_CLIENT_MODE_MANAGER";
1997                 case CMD_REQUEST_ADDITIONAL_CLIENT_MODE_MANAGER:
1998                     return "CMD_REQUEST_ADDITIONAL_CLIENT_MODE_MANAGER";
1999                 case CMD_EMERGENCY_SCAN_STATE_CHANGED:
2000                     return "CMD_EMERGENCY_SCAN_STATE_CHANGED";
2001                 case CMD_SCAN_ALWAYS_MODE_CHANGED:
2002                     return "CMD_SCAN_ALWAYS_MODE_CHANGED";
2003                 case CMD_SET_AP:
2004                     return "CMD_SET_AP";
2005                 case CMD_STA_START_FAILURE:
2006                     return "CMD_STA_START_FAILURE";
2007                 case CMD_STA_STOPPED:
2008                     return "CMD_STA_STOPPED";
2009                 case CMD_UPDATE_AP_CAPABILITY:
2010                     return "CMD_UPDATE_AP_CAPABILITY";
2011                 case CMD_UPDATE_AP_CONFIG:
2012                     return "CMD_UPDATE_AP_CONFIG";
2013                 case CMD_WIFI_TOGGLED:
2014                     return "CMD_WIFI_TOGGLED";
2015                 case CMD_SATELLITE_MODE_CHANGED:
2016                     return "CMD_SATELLITE_MODE_CHANGED";
2017                 case RunnerState.STATE_ENTER_CMD:
2018                     return "Enter";
2019                 case RunnerState.STATE_EXIT_CMD:
2020                     return "Exit";
2021                 default:
2022                     return "what:" + what;
2023             }
2024         }
2025 
2026         @Override
start()2027         public void start() {
2028             boolean isAirplaneModeOn = mSettingsStore.isAirplaneModeOn();
2029             boolean isWifiEnabled = mSettingsStore.isWifiToggleEnabled();
2030             boolean isScanningAlwaysAvailable = mSettingsStore.isScanAlwaysAvailable();
2031             boolean isLocationModeActive = mWifiPermissionsUtil.isLocationModeEnabled();
2032             boolean isSatelliteModeOn = mSettingsStore.isSatelliteModeOn();
2033 
2034             log("isAirplaneModeOn = " + isAirplaneModeOn
2035                     + ", isWifiEnabled = " + isWifiEnabled
2036                     + ", isScanningAvailable = " + isScanningAlwaysAvailable
2037                     + ", isLocationModeActive = " + isLocationModeActive
2038                     + ", isSatelliteModeOn = " + isSatelliteModeOn);
2039 
2040             // Initialize these values at bootup to defaults, will be overridden by API calls
2041             // for further toggles.
2042             mLastPrimaryClientModeManagerRequestorWs = mFacade.getSettingsWorkSource(mContext);
2043             mLastScanOnlyClientModeManagerRequestorWs = INTERNAL_REQUESTOR_WS;
2044             ActiveModeManager.ClientRole role = getRoleForPrimaryOrScanOnlyClientModeManager();
2045             if (role == ROLE_CLIENT_PRIMARY) {
2046                 startPrimaryClientModeManager(mLastPrimaryClientModeManagerRequestorWs);
2047                 setInitialState(mEnabledState);
2048             } else if (role == ROLE_CLIENT_SCAN_ONLY) {
2049                 startScanOnlyClientModeManager(mLastScanOnlyClientModeManagerRequestorWs);
2050                 setInitialState(mEnabledState);
2051             } else {
2052                 setInitialState(mDisabledState);
2053             }
2054             mWifiMetrics.noteWifiEnabledDuringBoot(mSettingsStore.isWifiToggleEnabled());
2055             if (mSettingsStore.isWifiToggleEnabled()) {
2056                 boolean isWifiWakeOn = mWifiInjector.getWakeupController().isUsable();
2057                 mWifiMetrics.reportWifiStateChanged(true, isWifiWakeOn, false);
2058                 if (mVerboseLoggingEnabled) {
2059                     Log.d(TAG, "logging wifi is on after boot. wifi wake state=" + isWifiWakeOn);
2060                 }
2061             }
2062 
2063             // Initialize the lower layers before we start.
2064             mWifiNative.initialize();
2065             super.start();
2066         }
2067 
readWifiRecoveryDelay()2068         private int readWifiRecoveryDelay() {
2069             int recoveryDelayMillis = mResourceCache.getInteger(
2070                     R.integer.config_wifi_framework_recovery_timeout_delay);
2071             if (recoveryDelayMillis > MAX_RECOVERY_TIMEOUT_DELAY_MS) {
2072                 recoveryDelayMillis = MAX_RECOVERY_TIMEOUT_DELAY_MS;
2073                 Log.w(TAG, "Overriding timeout delay with maximum limit value");
2074             }
2075             return recoveryDelayMillis;
2076         }
2077 
2078         abstract class BaseState extends RunnerState {
BaseState(int threshold, @NonNull LocalLog localLog)2079             BaseState(int threshold, @NonNull LocalLog localLog) {
2080                 super(threshold, localLog);
2081             }
2082 
2083             @VisibleForTesting
isInEmergencyMode()2084             boolean isInEmergencyMode() {
2085                 return mIsInEmergencyCall || mIsInEmergencyCallbackMode;
2086             }
2087 
2088             /** Device is in emergency mode & carrier config requires wifi off in emergency mode */
isInEmergencyModeWhichRequiresWifiDisable()2089             private boolean isInEmergencyModeWhichRequiresWifiDisable() {
2090                 return isInEmergencyMode() && mFacade.getConfigWiFiDisableInECBM(mContext);
2091             }
2092 
updateEmergencyMode(Message msg)2093             private void updateEmergencyMode(Message msg) {
2094                 if (msg.what == CMD_EMERGENCY_CALL_STATE_CHANGED) {
2095                     mIsInEmergencyCall = msg.arg1 == 1;
2096                 } else if (msg.what == CMD_EMERGENCY_MODE_CHANGED) {
2097                     mIsInEmergencyCallbackMode = msg.arg1 == 1;
2098                 }
2099             }
2100 
enterEmergencyMode()2101             private void enterEmergencyMode() {
2102                 stopSoftApModeManagers(WifiManager.IFACE_IP_MODE_UNSPECIFIED);
2103                 boolean configWiFiDisableInECBM = mFacade.getConfigWiFiDisableInECBM(mContext);
2104                 log("Entering emergency callback mode, "
2105                         + "CarrierConfigManager.KEY_CONFIG_WIFI_DISABLE_IN_ECBM: "
2106                         + configWiFiDisableInECBM);
2107                 if (!mIsEmergencyScanInProgress) {
2108                     if (configWiFiDisableInECBM) {
2109                         shutdownWifi();
2110                     }
2111                 } else {
2112                     if (configWiFiDisableInECBM) {
2113                         switchAllPrimaryClientModeManagersToScanOnlyMode(
2114                                 mFacade.getSettingsWorkSource(mContext));
2115                     }
2116                 }
2117             }
2118 
exitEmergencyMode()2119             private void exitEmergencyMode() {
2120                 log("Exiting emergency callback mode");
2121                 // may be in DisabledState or EnabledState (depending on whether Wifi was shut down
2122                 // in enterEmergencyMode() or not based on getConfigWiFiDisableInECBM).
2123                 // Let CMD_WIFI_TOGGLED handling decide what the next state should be, or if we're
2124                 // already in the correct state.
2125 
2126                 // Assumes user toggled it on from settings before.
2127                 wifiToggled(mFacade.getSettingsWorkSource(mContext));
2128             }
2129 
processMessageInEmergencyMode(Message msg)2130             private boolean processMessageInEmergencyMode(Message msg) {
2131                 // In emergency mode: Some messages need special handling in this mode,
2132                 // all others are dropped.
2133                 switch (msg.what) {
2134                     case CMD_STA_STOPPED:
2135                     case CMD_AP_STOPPED:
2136                         log("Processing message in Emergency Callback Mode: " + msg);
2137                         if (!hasAnyModeManager()) {
2138                             log("No active mode managers, return to DisabledState.");
2139                             transitionTo(mDisabledState);
2140                         }
2141                         break;
2142                     case CMD_SET_AP:
2143                         // arg1 == 1 => enable AP
2144                         if (msg.arg1 == 1) {
2145                             log("AP cannot be started in Emergency Callback Mode: " + msg);
2146                             // SoftAP was disabled upon entering emergency mode. It also cannot
2147                             // be re-enabled during emergency mode. Drop the message and invoke
2148                             // the failure callback.
2149                             Pair<SoftApModeConfiguration, WorkSource> softApConfigAndWs =
2150                                     (Pair<SoftApModeConfiguration, WorkSource>) msg.obj;
2151                             SoftApModeConfiguration softApConfig = softApConfigAndWs.first;
2152                             WifiServiceImpl.SoftApCallbackInternal callback =
2153                                     softApConfig.getTargetMode() == IFACE_IP_MODE_LOCAL_ONLY
2154                                             ? mLohsCallback : mSoftApCallback;
2155                             // need to notify SoftApCallback that start/stop AP failed
2156                             callback.onStateChanged(new SoftApState(
2157                                     WIFI_AP_STATE_FAILED, SAP_START_FAILURE_GENERAL,
2158                                     softApConfig.getTetheringRequest(), null /* iface */));
2159                         }
2160                         break;
2161                     default:
2162                         log("Dropping message in emergency callback mode: " + msg);
2163                         break;
2164 
2165                 }
2166                 return HANDLED;
2167             }
2168 
handleEmergencyModeStateChange(Message msg)2169             private void handleEmergencyModeStateChange(Message msg) {
2170                 boolean wasInEmergencyMode = isInEmergencyMode();
2171                 updateEmergencyMode(msg);
2172                 boolean isInEmergencyMode = isInEmergencyMode();
2173                 if (!wasInEmergencyMode && isInEmergencyMode) {
2174                     enterEmergencyMode();
2175                 } else if (wasInEmergencyMode && !isInEmergencyMode) {
2176                     exitEmergencyMode();
2177                 }
2178             }
2179 
handleEmergencyScanStateChange(Message msg)2180             private void handleEmergencyScanStateChange(Message msg) {
2181                 final boolean scanInProgress = msg.arg1 == 1;
2182                 final WorkSource requestorWs = (WorkSource) msg.obj;
2183                 log("Processing scan state change: " + scanInProgress);
2184                 mIsEmergencyScanInProgress = scanInProgress;
2185                 if (isInEmergencyModeWhichRequiresWifiDisable())  {
2186                     // If wifi was disabled because of emergency mode
2187                     // (getConfigWiFiDisableInECBM == true), don't use the
2188                     // generic method to handle toggle change since that may put wifi in
2189                     // connectivity mode (since wifi toggle may actually be on underneath)
2190                     if (getCurrentState() == mDisabledState && scanInProgress) {
2191                         // go to scan only mode.
2192                         startScanOnlyClientModeManager(requestorWs);
2193                         transitionTo(mEnabledState);
2194                     } else if (getCurrentState() == mEnabledState && !scanInProgress) {
2195                         // shut down to go back to previous state.
2196                         stopAllClientModeManagers();
2197                     }
2198                 } else {
2199                     if (getCurrentState() == mDisabledState) {
2200                         handleStaToggleChangeInDisabledState(requestorWs);
2201                     } else if (getCurrentState() == mEnabledState) {
2202                         handleStaToggleChangeInEnabledState(requestorWs);
2203                     }
2204                 }
2205             }
2206 
2207             @Override
enterImpl()2208             public void enterImpl() {
2209             }
2210 
2211             @Override
exitImpl()2212             public void exitImpl() {
2213             }
2214 
2215             @Override
getMessageLogRec(int what)2216             public String getMessageLogRec(int what) {
2217                 return ActiveModeWarden.class.getSimpleName() + "."
2218                         + DefaultState.class.getSimpleName() + "." + getWhatToString(what);
2219             }
2220 
2221             @Override
processMessageImpl(Message msg)2222             public final boolean processMessageImpl(Message msg) {
2223                 // potentially enter emergency mode
2224                 if (msg.what == CMD_EMERGENCY_CALL_STATE_CHANGED
2225                         || msg.what == CMD_EMERGENCY_MODE_CHANGED) {
2226                     handleEmergencyModeStateChange(msg);
2227                     return HANDLED;
2228                 } else if (msg.what == CMD_EMERGENCY_SCAN_STATE_CHANGED) {
2229                     // emergency scans need to be allowed even in emergency mode.
2230                     handleEmergencyScanStateChange(msg);
2231                     return HANDLED;
2232                 } else if (isInEmergencyMode()) {
2233                     return processMessageInEmergencyMode(msg);
2234                 } else {
2235                     // not in emergency mode, process messages normally
2236                     return processMessageFiltered(msg);
2237                 }
2238             }
2239 
processMessageFiltered(Message msg)2240             protected abstract boolean processMessageFiltered(Message msg);
2241         }
2242 
2243         class DefaultState extends RunnerState {
DefaultState(int threshold)2244             DefaultState(int threshold) {
2245                 super(threshold, mWifiInjector.getWifiHandlerLocalLog());
2246             }
2247 
2248             @Override
getMessageLogRec(int what)2249             public String getMessageLogRec(int what) {
2250                 return ActiveModeWarden.class.getSimpleName() + "."
2251                         + DefaultState.class.getSimpleName() + "." + getWhatToString(what);
2252             }
2253 
2254             @Override
enterImpl()2255             public void enterImpl() {
2256             }
2257 
2258             @Override
exitImpl()2259             public void exitImpl() {
2260             }
2261 
checkAndHandleAirplaneModeState(String loggingPackageName)2262             private void checkAndHandleAirplaneModeState(String loggingPackageName) {
2263                 if (mSettingsStore.isAirplaneModeOn()) {
2264                     log("Airplane mode toggled");
2265                     if (!mSettingsStore.shouldWifiRemainEnabledWhenApmEnabled()) {
2266                         log("Wifi disabled on APM, disable wifi");
2267                         shutdownWifi();
2268                         // onStopped will move the state machine to "DisabledState".
2269                         mLastCallerInfoManager.put(WifiManager.API_WIFI_ENABLED, Process.myTid(),
2270                                 Process.WIFI_UID, -1, loggingPackageName, false);
2271                     }
2272                 } else {
2273                     log("Airplane mode disabled, determine next state");
2274                     if (shouldEnableSta()) {
2275                         startPrimaryOrScanOnlyClientModeManager(
2276                                 // Assumes user toggled it on from settings before.
2277                                 mFacade.getSettingsWorkSource(mContext));
2278                         transitionTo(mEnabledState);
2279                         mLastCallerInfoManager.put(WifiManager.API_WIFI_ENABLED, Process.myTid(),
2280                                 Process.WIFI_UID, -1, loggingPackageName, true);
2281                     }
2282                     // wifi should remain disabled, do not need to transition
2283                 }
2284             }
2285 
2286             @Override
processMessageImpl(Message msg)2287             public boolean processMessageImpl(Message msg) {
2288                 switch (msg.what) {
2289                     case CMD_SCAN_ALWAYS_MODE_CHANGED:
2290                     case CMD_EMERGENCY_SCAN_STATE_CHANGED:
2291                     case CMD_WIFI_TOGGLED:
2292                     case CMD_STA_STOPPED:
2293                     case CMD_STA_START_FAILURE:
2294                     case CMD_AP_STOPPED:
2295                     case CMD_AP_START_FAILURE:
2296                     case CMD_RECOVERY_RESTART_WIFI:
2297                     case CMD_RECOVERY_RESTART_WIFI_CONTINUE:
2298                     case CMD_DEFERRED_RECOVERY_RESTART_WIFI:
2299                     case CMD_REMOVE_ADDITIONAL_CLIENT_MODE_MANAGER:
2300                         break;
2301                     case CMD_REQUEST_ADDITIONAL_CLIENT_MODE_MANAGER:
2302                         AdditionalClientModeManagerRequestInfo requestInfo =
2303                                 (AdditionalClientModeManagerRequestInfo) msg.obj;
2304                         requestInfo.listener.onAnswer(null);
2305                         break;
2306                     case CMD_RECOVERY_DISABLE_WIFI:
2307                         log("Recovery has been throttled, disable wifi");
2308                         shutdownWifi();
2309                         // onStopped will move the state machine to "DisabledState".
2310                         break;
2311                     case CMD_AIRPLANE_TOGGLED:
2312                         if (mSettingsStore.isSatelliteModeOn()) {
2313                             log("Satellite mode is on - return");
2314                             break;
2315                         }
2316                         checkAndHandleAirplaneModeState("android_apm");
2317                         break;
2318                     case CMD_UPDATE_AP_CAPABILITY:
2319                         updateCapabilityToSoftApModeManager((SoftApCapability) msg.obj, msg.arg1);
2320                         break;
2321                     case CMD_UPDATE_AP_CONFIG:
2322                         updateConfigurationToSoftApModeManager((SoftApConfiguration) msg.obj);
2323                         break;
2324                     case CMD_SATELLITE_MODE_CHANGED:
2325                         if (mSettingsStore.isSatelliteModeOn()) {
2326                             log("Satellite mode is on, disable wifi");
2327                             shutdownWifi();
2328                             mLastCallerInfoManager.put(WifiManager.API_WIFI_ENABLED,
2329                                     Process.myTid(), Process.WIFI_UID, -1, "satellite_mode",
2330                                     false);
2331                         } else {
2332                             log("Satellite mode is off, determine next stage");
2333                             checkAndHandleAirplaneModeState("satellite_mode");
2334                         }
2335                         break;
2336                     default:
2337                         throw new RuntimeException("WifiController.handleMessage " + msg.what);
2338                 }
2339                 return HANDLED;
2340             }
2341         }
2342 
shouldEnableScanOnlyMode()2343         private boolean shouldEnableScanOnlyMode() {
2344             return (mWifiPermissionsUtil.isLocationModeEnabled()
2345                     && mSettingsStore.isScanAlwaysAvailable())
2346                     || mIsEmergencyScanInProgress;
2347         }
2348 
shouldEnableSta()2349         private boolean shouldEnableSta() {
2350             return (mSettingsStore.isWifiToggleEnabled() || shouldEnableScanOnlyMode())
2351                     && !mSettingsStore.isSatelliteModeOn();
2352         }
2353 
handleStaToggleChangeInDisabledState(WorkSource requestorWs)2354         private void handleStaToggleChangeInDisabledState(WorkSource requestorWs) {
2355             if (shouldEnableSta()) {
2356                 startPrimaryOrScanOnlyClientModeManager(requestorWs);
2357                 transitionTo(mEnabledState);
2358             }
2359         }
2360 
handleStaToggleChangeInEnabledState(WorkSource requestorWs)2361         private void handleStaToggleChangeInEnabledState(WorkSource requestorWs) {
2362             if (shouldEnableSta()) {
2363                 if (hasPrimaryOrScanOnlyModeManager()) {
2364                     if (!mSettingsStore.isWifiToggleEnabled()) {
2365                         // Wifi is turned off, so we should stop all the secondary CMMs which are
2366                         // currently all for connectivity purpose. It's important to stops the
2367                         // secondary CMMs before switch state of the primary CMM so features using
2368                         // those secondary CMMs knows to abort properly, and won't react in strange
2369                         // ways to the primary switching to scan only mode later.
2370                         stopSecondaryClientModeManagers();
2371                         mWifiInjector.getWifiConnectivityManager().resetOnWifiDisable();
2372                     }
2373                     switchAllPrimaryOrScanOnlyClientModeManagers();
2374                 } else {
2375                     startPrimaryOrScanOnlyClientModeManager(requestorWs);
2376                 }
2377             } else {
2378                 stopAllClientModeManagers();
2379                 mWifiInjector.getWifiConnectivityManager().resetOnWifiDisable();
2380             }
2381         }
2382 
2383         class DisabledState extends BaseState {
DisabledState(int threshold)2384             DisabledState(int threshold) {
2385                 super(threshold, mWifiInjector.getWifiHandlerLocalLog());
2386             }
2387 
2388             @Override
enterImpl()2389             public void enterImpl() {
2390                 log("DisabledState.enter()");
2391                 super.enterImpl();
2392                 if (hasAnyModeManager()) {
2393                     Log.e(TAG, "Entered DisabledState, but has active mode managers");
2394                 }
2395             }
2396 
2397             @Override
exitImpl()2398             public void exitImpl() {
2399                 log("DisabledState.exit()");
2400                 super.exitImpl();
2401             }
2402 
2403             @Override
processMessageFiltered(Message msg)2404             public boolean processMessageFiltered(Message msg) {
2405                 switch (msg.what) {
2406                     case CMD_WIFI_TOGGLED:
2407                     case CMD_SCAN_ALWAYS_MODE_CHANGED:
2408                         handleStaToggleChangeInDisabledState((WorkSource) msg.obj);
2409                         break;
2410                     case CMD_SET_AP:
2411                         // note: CMD_SET_AP is handled/dropped in ECM mode - will not start here
2412                         if (msg.arg1 == 1) {
2413                             Pair<SoftApModeConfiguration, WorkSource> softApConfigAndWs =
2414                                     (Pair) msg.obj;
2415                             startSoftApModeManager(
2416                                     softApConfigAndWs.first, softApConfigAndWs.second);
2417                             transitionTo(mEnabledState);
2418                         }
2419                         break;
2420                     case CMD_RECOVERY_RESTART_WIFI:
2421                         log("Recovery triggered, already in disabled state");
2422                         sendMessageDelayed(CMD_RECOVERY_RESTART_WIFI_CONTINUE,
2423                                 Collections.emptyList(), readWifiRecoveryDelay());
2424                         break;
2425                     case CMD_DEFERRED_RECOVERY_RESTART_WIFI:
2426                         // wait mRecoveryDelayMillis for letting driver clean reset.
2427                         sendMessageDelayed(CMD_RECOVERY_RESTART_WIFI_CONTINUE,
2428                                 msg.obj, readWifiRecoveryDelay());
2429                         break;
2430                     case CMD_RECOVERY_RESTART_WIFI_CONTINUE:
2431                         log("Recovery in progress, start wifi");
2432                         List<ActiveModeManager> modeManagersBeforeRecovery = (List) msg.obj;
2433                         // No user controlled mode managers before recovery, so check if wifi
2434                         // was toggled on.
2435                         if (modeManagersBeforeRecovery.isEmpty()) {
2436                             if (shouldEnableSta()) {
2437                                 startPrimaryOrScanOnlyClientModeManager(
2438                                         // Assumes user toggled it on from settings before.
2439                                         mFacade.getSettingsWorkSource(mContext));
2440                                 transitionTo(mEnabledState);
2441                             }
2442                             break;
2443                         }
2444                         for (ActiveModeManager activeModeManager : modeManagersBeforeRecovery) {
2445                             if (activeModeManager instanceof ConcreteClientModeManager) {
2446                                 startPrimaryOrScanOnlyClientModeManager(
2447                                         activeModeManager.getRequestorWs());
2448                             } else if (activeModeManager instanceof SoftApManager) {
2449                                 SoftApManager softApManager = (SoftApManager) activeModeManager;
2450                                 startSoftApModeManager(
2451                                         softApManager.getSoftApModeConfiguration(),
2452                                         softApManager.getRequestorWs());
2453                             }
2454                         }
2455                         transitionTo(mEnabledState);
2456                         int numCallbacks = mRestartCallbacks.beginBroadcast();
2457                         for (int i = 0; i < numCallbacks; i++) {
2458                             try {
2459                                 mRestartCallbacks.getBroadcastItem(i).onSubsystemRestarted();
2460                             } catch (RemoteException e) {
2461                                 Log.e(TAG, "Failure calling onSubsystemRestarted" + e);
2462                             }
2463                         }
2464                         mRestartCallbacks.finishBroadcast();
2465                         mWifiInjector.getSelfRecovery().onRecoveryCompleted();
2466                         break;
2467                     default:
2468                         return NOT_HANDLED;
2469                 }
2470                 return HANDLED;
2471             }
2472         }
2473 
2474         class EnabledState extends BaseState {
EnabledState(int threshold)2475             EnabledState(int threshold) {
2476                 super(threshold, mWifiInjector.getWifiHandlerLocalLog());
2477             }
2478 
2479             @Override
enterImpl()2480             public void enterImpl() {
2481                 log("EnabledState.enter()");
2482                 super.enterImpl();
2483                 if (!hasAnyModeManager()) {
2484                     Log.e(TAG, "Entered EnabledState, but no active mode managers");
2485                 }
2486             }
2487 
2488             @Override
exitImpl()2489             public void exitImpl() {
2490                 log("EnabledState.exit()");
2491                 if (hasAnyModeManager()) {
2492                     Log.e(TAG, "Exiting EnabledState, but has active mode managers");
2493                 }
2494                 super.exitImpl();
2495             }
2496 
2497             @Nullable
findAnyClientModeManagerConnectingOrConnectedToBssid( @onNull String ssid, @Nullable String bssid)2498             private ConcreteClientModeManager findAnyClientModeManagerConnectingOrConnectedToBssid(
2499                     @NonNull String ssid, @Nullable String bssid) {
2500                 if (bssid == null) {
2501                     return null;
2502                 }
2503                 for (ConcreteClientModeManager cmm : mClientModeManagers) {
2504                     if (isClientModeManagerConnectedOrConnectingToBssid(cmm, ssid, bssid)) {
2505                         return cmm;
2506                     }
2507                 }
2508                 return null;
2509             }
2510 
handleAdditionalClientModeManagerRequest( @onNull AdditionalClientModeManagerRequestInfo requestInfo)2511             private void handleAdditionalClientModeManagerRequest(
2512                     @NonNull AdditionalClientModeManagerRequestInfo requestInfo) {
2513                 if (mWifiState.get() == WIFI_STATE_DISABLING
2514                         || mWifiState.get() == WIFI_STATE_DISABLED) {
2515                     // Do no allow getting secondary CMM when wifi is being disabled or disabled.
2516                     requestInfo.listener.onAnswer(null);
2517                     return;
2518                 }
2519 
2520                 ClientModeManager primaryManager = getPrimaryClientModeManagerNullable();
2521                 // TODO(b/228529090): Remove this special code once root cause is resolved.
2522                 // Special case for holders with ENTER_CAR_MODE_PRIORITIZED. Only give them the
2523                 // primary STA to avoid the device getting into STA+STA state.
2524                 // In STA+STA wifi scans will result in high latency in the secondary STA.
2525                 if (!requestInfo.preferSecondarySta
2526                         && requestInfo.clientRole == ROLE_CLIENT_LOCAL_ONLY
2527                         && requestInfo.requestorWs != null) {
2528                     WorkSource workSource = requestInfo.requestorWs;
2529                     for (int i = 0; i < workSource.size(); i++) {
2530                         int curUid = workSource.getUid(i);
2531                         if (mAllowRootToGetLocalOnlyCmm && curUid == 0) { // 0 is root UID.
2532                             continue;
2533                         }
2534                         if (curUid != Process.SYSTEM_UID
2535                                 && mWifiPermissionsUtil.checkEnterCarModePrioritized(curUid)) {
2536                             requestInfo.listener.onAnswer(primaryManager);
2537                             if (mVerboseLoggingEnabled) {
2538                                 Log.w(TAG, "Uid " + curUid
2539                                         + " has car mode permission - disabling STA+STA");
2540                             }
2541                             return;
2542                         }
2543                     }
2544                 }
2545                 if (requestInfo.clientRole == ROLE_CLIENT_SECONDARY_TRANSIENT
2546                         && mDppManager.isSessionInProgress()) {
2547                     // When MBB is triggered, we could end up switching the primary interface
2548                     // after completion. So if we have any DPP session in progress, they will fail
2549                     // when the previous primary iface is removed after MBB completion.
2550                     Log.v(TAG, "DPP session in progress, fallback to single STA behavior "
2551                             + "using primary ClientModeManager=" + primaryManager);
2552                     requestInfo.listener.onAnswer(primaryManager);
2553                     return;
2554                 }
2555                 ConcreteClientModeManager cmmForSameBssid =
2556                         findAnyClientModeManagerConnectingOrConnectedToBssid(
2557                                 requestInfo.ssid, requestInfo.bssid);
2558                 if (cmmForSameBssid != null) {
2559                     // Can't allow 2 client mode managers triggering connection to same bssid.
2560                     Log.v(TAG, "Already connected to bssid=" + requestInfo.bssid
2561                             + " on ClientModeManager=" + cmmForSameBssid);
2562                     if (cmmForSameBssid.getRole() == ROLE_CLIENT_PRIMARY) {
2563                         // fallback to single STA behavior.
2564                         requestInfo.listener.onAnswer(cmmForSameBssid);
2565                         return;
2566                     }
2567                     // The CMM having BSSID conflict is exactly the one being requested.
2568                     // Simply return the CMM in this case. The requestor will be responsible to
2569                     // make sure it does not trigger the connection again when already connected.
2570                     if (cmmForSameBssid.getRole() == requestInfo.clientRole) {
2571                         requestInfo.listener.onAnswer(cmmForSameBssid);
2572                         return;
2573                     }
2574                     // Existing secondary CMM connected to the same ssid/bssid.
2575                     if (!canRequestMoreClientModeManagersInRole(requestInfo.requestorWs,
2576                             requestInfo.clientRole, requestInfo.didUserApprove)) {
2577                         Log.e(TAG, "New request cannot override existing request on "
2578                                 + "ClientModeManager=" + cmmForSameBssid);
2579                         // If the new request does not have priority over the existing request,
2580                         // reject it since we cannot have 2 CMM's connected to same ssid/bssid.
2581                         requestInfo.listener.onAnswer(null);
2582                         return;
2583                     }
2584                     // If the new request has a higher priority over the existing one, change it's
2585                     // role and send it to the new client.
2586                     // Switch role for non primary CMM & wait for it to complete before
2587                     // handing it to the requestor.
2588                     switchRoleForAdditionalClientModeManager(
2589                             cmmForSameBssid, requestInfo.clientRole, requestInfo.listener,
2590                             requestInfo.requestorWs);
2591                     return;
2592                 }
2593 
2594                 ClientModeManager cmmForSameRole =
2595                         getClientModeManagerInRole(requestInfo.clientRole);
2596                 if (cmmForSameRole != null) {
2597                     // Already have a client mode manager in the requested role.
2598                     // Note: This logic results in the framework not supporting more than 1 CMM in
2599                     // the same role concurrently. There is no use-case for that currently &
2600                     // none of the clients (i.e WifiNetworkFactory, WifiConnectivityManager, etc)
2601                     // are ready to support that either. If this assumption changes in the future
2602                     // when the device supports 3 STA's for example, change this logic!
2603                     Log.v(TAG, "Already exists ClientModeManager for role: " + cmmForSameRole);
2604                     requestInfo.listener.onAnswer(cmmForSameRole);
2605                     return;
2606                 }
2607                 if (canRequestMoreClientModeManagersInRole(requestInfo.requestorWs,
2608                         requestInfo.clientRole, requestInfo.didUserApprove)) {
2609                     // Can create an additional client mode manager.
2610                     Log.v(TAG, "Starting a new ClientModeManager");
2611                     WorkSource ifCreatorWs = new WorkSource(requestInfo.requestorWs);
2612                     if (requestInfo.didUserApprove) {
2613                         // If user select to connect from the UI, promote the priority
2614                         ifCreatorWs.add(mFacade.getSettingsWorkSource(mContext));
2615                     }
2616                     startAdditionalClientModeManager(requestInfo.clientRole, requestInfo.listener,
2617                             ifCreatorWs);
2618                     return;
2619                 }
2620 
2621                 // fallback decision
2622                 if (requestInfo.clientRole == ROLE_CLIENT_LOCAL_ONLY
2623                         && isStaStaConcurrencySupportedForLocalOnlyConnections()
2624                         && !mWifiPermissionsUtil.isTargetSdkLessThan(
2625                         requestInfo.requestorWs.getPackageName(0), Build.VERSION_CODES.S,
2626                         requestInfo.requestorWs.getUid(0))) {
2627                     Log.d(TAG, "Will not fall back to single STA for a local-only connection when "
2628                             + "STA+STA is supported (unless for a pre-S legacy app). "
2629                             + " Priority inversion.");
2630                     requestInfo.listener.onAnswer(null);
2631                     return;
2632                 }
2633 
2634                 // Fall back to single STA behavior.
2635                 Log.v(TAG, "Falling back to single STA behavior using primary ClientModeManager="
2636                         + primaryManager);
2637                 requestInfo.listener.onAnswer(primaryManager);
2638             }
2639 
2640             @Override
processMessageFiltered(Message msg)2641             public boolean processMessageFiltered(Message msg) {
2642                 switch (msg.what) {
2643                     case CMD_WIFI_TOGGLED:
2644                     case CMD_SCAN_ALWAYS_MODE_CHANGED:
2645                         handleStaToggleChangeInEnabledState((WorkSource) msg.obj);
2646                         break;
2647                     case CMD_REQUEST_ADDITIONAL_CLIENT_MODE_MANAGER:
2648                         handleAdditionalClientModeManagerRequest(
2649                                 (AdditionalClientModeManagerRequestInfo) msg.obj);
2650                         break;
2651                     case CMD_REMOVE_ADDITIONAL_CLIENT_MODE_MANAGER:
2652                         stopAdditionalClientModeManager((ClientModeManager) msg.obj);
2653                         break;
2654                     case CMD_SET_AP:
2655                         // note: CMD_SET_AP is handled/dropped in ECM mode - will not start here
2656                         if (msg.arg1 == 1) {
2657                             Pair<SoftApModeConfiguration, WorkSource> softApConfigAndWs =
2658                                     (Pair) msg.obj;
2659                             startSoftApModeManager(
2660                                     softApConfigAndWs.first, softApConfigAndWs.second);
2661                         } else {
2662                             stopSoftApModeManagers(msg.arg2);
2663                         }
2664                         break;
2665                     case CMD_AIRPLANE_TOGGLED:
2666                         // airplane mode toggled on is handled in the default state
2667                         if (mSettingsStore.isAirplaneModeOn()) {
2668                             return NOT_HANDLED;
2669                         } else {
2670                             if (mWifiState.get() == WIFI_STATE_DISABLING) {
2671                                 // Previous airplane mode toggle on is being processed, defer the
2672                                 // message toggle off until previous processing is completed.
2673                                 // Once previous airplane mode toggle is complete, we should
2674                                 // transition to DisabledState. There, we will process the deferred
2675                                 // airplane mode toggle message to disable airplane mode.
2676                                 Log.i(TAG, "Deferring CMD_AIRPLANE_TOGGLED.");
2677                                 deferMessage(msg);
2678                             } else {
2679                                 if (!hasPrimaryOrScanOnlyModeManager()) {
2680                                     // SoftAp was enabled during airplane mode and caused
2681                                     // WifiController to be in EnabledState without
2682                                     // a primary client mode manager.
2683                                     // Defer to the default state to handle the airplane mode toggle
2684                                     // which may result in enabling wifi if necessary.
2685                                     log("airplane mode toggled - and no primary manager");
2686                                     return NOT_HANDLED;
2687                                 }
2688                                 // when airplane mode is toggled off, but wifi is on, we can keep it
2689                                 // on
2690                                 log("airplane mode toggled - and airplane mode is off. return "
2691                                         + "handled");
2692                             }
2693                             return HANDLED;
2694                         }
2695                     case CMD_SATELLITE_MODE_CHANGED:
2696                         if (mSettingsStore.isSatelliteModeOn()) {
2697                             log("Satellite mode is on, disable wifi");
2698                             shutdownWifi();
2699                             mLastCallerInfoManager.put(WifiManager.API_WIFI_ENABLED,
2700                                     Process.myTid(), Process.WIFI_UID, -1, "satellite_mode",
2701                                     false);
2702                         } else {
2703                             if (!hasPrimaryOrScanOnlyModeManager()) {
2704                                 // Enabling SoftAp while wifi is off could result in
2705                                 // ActiveModeWarden being in enabledState without a CMM.
2706                                 // Defer to the default state in this case to handle the satellite
2707                                 // mode state change which may result in enabling wifi if necessary.
2708                                 log("Satellite mode is off in enabled state - "
2709                                         + "and no primary manager");
2710                                 return NOT_HANDLED;
2711                             }
2712                             log("Satellite mode is off in enabled state. Return handled");
2713                         }
2714                         break;
2715                     case CMD_AP_STOPPED:
2716                     case CMD_AP_START_FAILURE:
2717                         if (hasAnyModeManager()) {
2718                             log("AP disabled, remain in EnabledState.");
2719                             break;
2720                         }
2721                         if (msg.what == CMD_AP_STOPPED) {
2722                             mWifiInjector.getSelfRecovery().onWifiStopped();
2723                             if (mWifiInjector.getSelfRecovery().isRecoveryInProgress()) {
2724                                 // Recovery in progress, transit to disabled state.
2725                                 transitionTo(mDisabledState);
2726                                 break;
2727                             }
2728                         }
2729                         if (shouldEnableSta()) {
2730                             log("SoftAp disabled, start client mode");
2731                             startPrimaryOrScanOnlyClientModeManager(
2732                                     // Assumes user toggled it on from settings before.
2733                                     mFacade.getSettingsWorkSource(mContext));
2734                         } else {
2735                             log("SoftAp mode disabled, return to DisabledState");
2736                             transitionTo(mDisabledState);
2737                         }
2738                         break;
2739                     case CMD_STA_START_FAILURE:
2740                     case CMD_STA_STOPPED:
2741                         // Client mode stopped. Head to Disabled to wait for next command if there
2742                         // is no active mode manager.
2743                         if (!hasAnyModeManager()) {
2744                             mWifiInjector.getSelfRecovery().onWifiStopped();
2745                             log("STA disabled, return to DisabledState.");
2746                             transitionTo(mDisabledState);
2747                         } else {
2748                             log("STA disabled, remain in EnabledState.");
2749                             // Handle any deferred airplane toggle off messages that didn't
2750                             // trigger due to no state change
2751                             if (hasDeferredMessages(CMD_AIRPLANE_TOGGLED)
2752                                     && !hasPrimaryOrScanOnlyModeManager()) {
2753                                 removeDeferredMessages(CMD_AIRPLANE_TOGGLED);
2754                                 if (mSettingsStore.isAirplaneModeOn()) {
2755                                     // deferred APM toggle is only meant to be done for APM off, so
2756                                     // no-op if APM is already on here.
2757                                     break;
2758                                 }
2759                                 log("Airplane mode disabled, determine next state");
2760                                 if (shouldEnableSta()) {
2761                                     startPrimaryOrScanOnlyClientModeManager(
2762                                             // Assumes user toggled it on from settings before.
2763                                             mFacade.getSettingsWorkSource(mContext));
2764                                     mLastCallerInfoManager.put(WifiManager.API_WIFI_ENABLED,
2765                                             Process.myTid(), Process.WIFI_UID, -1, "android_apm",
2766                                             true);
2767                                 }
2768                             }
2769                         }
2770                         break;
2771                     case  CMD_DEFERRED_RECOVERY_RESTART_WIFI:
2772                         // Wifi shutdown is not completed yet, still in enabled state.
2773                         // Defer the message and wait for entering disabled state.
2774                         deferMessage(msg);
2775                         break;
2776                     case CMD_RECOVERY_RESTART_WIFI: {
2777                         final String bugTitle;
2778                         final String bugDetail = (String) msg.obj;
2779                         if (TextUtils.isEmpty(bugDetail)) {
2780                             bugTitle = "Wi-Fi BugReport";
2781                         } else {
2782                             bugTitle = "Wi-Fi BugReport: " + bugDetail;
2783                         }
2784                         log("Recovery triggered, disable wifi");
2785                         boolean bugReportRequested = msg.arg2 != 0;
2786                         if (bugReportRequested) {
2787                             mHandler.post(() ->
2788                                     mWifiDiagnostics.takeBugReport(bugTitle, bugDetail));
2789                         }
2790                         // Store all instances of tethered SAP + scan only/primary STA mode managers
2791                         List<ActiveModeManager> modeManagersBeforeRecovery = Stream.concat(
2792                                 mClientModeManagers.stream()
2793                                         .filter(m -> ROLE_CLIENT_SCAN_ONLY.equals(m.getRole())
2794                                                 || ROLE_CLIENT_PRIMARY.equals(m.getRole())),
2795                                 mSoftApManagers.stream()
2796                                         .filter(m -> ROLE_SOFTAP_TETHERED.equals(m.getRole())))
2797                                 .collect(Collectors.toList());
2798                         deferMessage(obtainMessage(CMD_DEFERRED_RECOVERY_RESTART_WIFI,
2799                                 modeManagersBeforeRecovery));
2800                         int numCallbacks = mRestartCallbacks.beginBroadcast();
2801                         for (int i = 0; i < numCallbacks; i++) {
2802                             try {
2803                                 mRestartCallbacks.getBroadcastItem(i).onSubsystemRestarting();
2804                             } catch (RemoteException e) {
2805                                 Log.e(TAG, "Failure calling onSubsystemRestarting" + e);
2806                             }
2807                         }
2808                         mRestartCallbacks.finishBroadcast();
2809                         shutdownWifi();
2810                         // onStopped will move the state machine to "DisabledState".
2811                         break;
2812                     }
2813                     case CMD_RECOVERY_RESTART_WIFI_CONTINUE: {
2814                         log("received CMD_RECOVERY_RESTART_WIFI_CONTINUE when already in "
2815                                 + "mEnabledState");
2816                         // This could happen when SoftAp is turned on before recovery is complete.
2817                         // Simply make sure the primary CMM is on in this case.
2818                         if (shouldEnableSta() && !hasPrimaryOrScanOnlyModeManager()) {
2819                             startPrimaryOrScanOnlyClientModeManager(
2820                                     // Assumes user toggled it on from settings before.
2821                                     mFacade.getSettingsWorkSource(mContext));
2822                         }
2823                         int numCallbacks = mRestartCallbacks.beginBroadcast();
2824                         for (int i = 0; i < numCallbacks; i++) {
2825                             try {
2826                                 mRestartCallbacks.getBroadcastItem(i).onSubsystemRestarted();
2827                             } catch (RemoteException e) {
2828                                 Log.e(TAG, "Failure calling onSubsystemRestarted" + e);
2829                             }
2830                         }
2831                         mRestartCallbacks.finishBroadcast();
2832                         mWifiInjector.getSelfRecovery().onRecoveryCompleted();
2833                         break;
2834                     }
2835                     default:
2836                         return NOT_HANDLED;
2837                 }
2838                 return HANDLED;
2839             }
2840         }
2841     }
2842 
coalesce(T a, T b)2843     private static <T> T coalesce(T a, T  b) {
2844         return a != null ? a : b;
2845     }
2846 
2847     /**
2848      * Check if CMM is connecting or connected to target BSSID and SSID
2849      */
isClientModeManagerConnectedOrConnectingToBssid( @onNull ClientModeManager clientModeManager, @NonNull String ssid, @NonNull String bssid)2850     public static boolean isClientModeManagerConnectedOrConnectingToBssid(
2851             @NonNull ClientModeManager clientModeManager,
2852             @NonNull String ssid, @NonNull String bssid) {
2853         WifiConfiguration connectedOrConnectingWifiConfiguration = coalesce(
2854                 clientModeManager.getConnectingWifiConfiguration(),
2855                 clientModeManager.getConnectedWifiConfiguration());
2856         String connectedOrConnectingBssid = coalesce(
2857                 clientModeManager.getConnectingBssid(),
2858                 clientModeManager.getConnectedBssid());
2859         String connectedOrConnectingSsid =
2860                 connectedOrConnectingWifiConfiguration == null
2861                         ? null : connectedOrConnectingWifiConfiguration.SSID;
2862         Log.v(TAG, connectedOrConnectingBssid + "   " + connectedOrConnectingSsid);
2863         return Objects.equals(ssid, connectedOrConnectingSsid)
2864                 && (Objects.equals(bssid, connectedOrConnectingBssid)
2865                 || clientModeManager.isAffiliatedLinkBssid(NativeUtil.getMacAddressOrNull(bssid)));
2866     }
2867 
2868     /**
2869      * Set the current supported Wifi feature set, called from primary client mode manager.
2870      * @param wifiNativeFeatureSet feature set retrieved from WifiNative
2871      * @param isStaApConcurrencySupported true if Sta+Ap concurrency supported
2872      * @param isStaStaConcurrencySupported true if Sta+Sta concurrency supported
2873      */
setSupportedFeatureSet(BitSet wifiNativeFeatureSet, boolean isStaApConcurrencySupported, boolean isStaStaConcurrencySupported)2874     private void setSupportedFeatureSet(BitSet wifiNativeFeatureSet,
2875             boolean isStaApConcurrencySupported,
2876             boolean isStaStaConcurrencySupported) {
2877         BitSet featureSet = (BitSet) wifiNativeFeatureSet.clone();
2878 
2879         // Concurrency features
2880         if (isStaApConcurrencySupported) {
2881             featureSet.set(WifiManager.WIFI_FEATURE_AP_STA);
2882         }
2883         if (isStaStaConcurrencySupported) {
2884             if (mResourceCache.getBoolean(
2885                     R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled)) {
2886                 featureSet.set(WifiManager.WIFI_FEATURE_ADDITIONAL_STA_LOCAL_ONLY);
2887             }
2888             if (mResourceCache.getBoolean(
2889                     R.bool.config_wifiMultiStaNetworkSwitchingMakeBeforeBreakEnabled)) {
2890                 featureSet.set(WifiManager.WIFI_FEATURE_ADDITIONAL_STA_MBB);
2891             }
2892             if (mResourceCache.getBoolean(
2893                     R.bool.config_wifiMultiStaRestrictedConcurrencyEnabled)) {
2894                 featureSet.set(WifiManager.WIFI_FEATURE_ADDITIONAL_STA_RESTRICTED);
2895             }
2896             if (mResourceCache.getBoolean(
2897                     R.bool.config_wifiMultiStaMultiInternetConcurrencyEnabled)) {
2898                 featureSet.set(WifiManager.WIFI_FEATURE_ADDITIONAL_STA_MULTI_INTERNET);
2899             }
2900         }
2901 
2902         // Additional features
2903         if (mResourceCache.getBoolean(
2904                 R.bool.config_wifi_connected_mac_randomization_supported)) {
2905             // no corresponding flags in vendor HAL, set if overlay enables it.
2906             featureSet.set(WifiManager.WIFI_FEATURE_CONNECTED_RAND_MAC);
2907         }
2908         if (ApConfigUtil.isApMacRandomizationSupported(mContext)) {
2909             // no corresponding flags in vendor HAL, set if overlay enables it.
2910             featureSet.set(WifiManager.WIFI_FEATURE_AP_RAND_MAC);
2911         }
2912         if (ApConfigUtil.isBridgedModeSupported(mContext, mWifiNative)) {
2913             // The bridged mode requires the kernel network modules support.
2914             // It doesn't relate the vendor HAL, set if overlay enables it.
2915             featureSet.set(WifiManager.WIFI_FEATURE_BRIDGED_AP);
2916         }
2917         if (ApConfigUtil.isStaWithBridgedModeSupported(mContext, mWifiNative)) {
2918             // The bridged mode requires the kernel network modules support.
2919             // It doesn't relate the vendor HAL, set if overlay enables it.
2920             featureSet.set(WifiManager.WIFI_FEATURE_STA_BRIDGED_AP);
2921         }
2922         if (mWifiGlobals.isWepSupported()) {
2923             featureSet.set(WifiManager.WIFI_FEATURE_WEP);
2924         }
2925 
2926         if (!mWifiGlobals.isWpaPersonalDeprecated()) {
2927             // The WPA didn't be deprecated, set it.
2928             featureSet.set(WifiManager.WIFI_FEATURE_WPA_PERSONAL);
2929         }
2930         if (mWifiGlobals.isD2dSupportedWhenInfraStaDisabled()) {
2931             featureSet.set(WifiManager.WIFI_FEATURE_D2D_WHEN_INFRA_STA_DISABLED);
2932         }
2933 
2934         // Remove capabilities that are disabled by the system properties
2935         if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_RTT)) {
2936             featureSet.clear(WifiManager.WIFI_FEATURE_D2D_RTT);
2937             featureSet.clear(WifiManager.WIFI_FEATURE_D2AP_RTT);
2938         }
2939         if (!mResourceCache.getBoolean(
2940                 R.bool.config_wifi_p2p_mac_randomization_supported)) {
2941             featureSet.clear(WifiManager.WIFI_FEATURE_P2P_RAND_MAC);
2942         }
2943 
2944         synchronized (mServiceApiLock) {
2945             mSupportedFeatureSet = featureSet;
2946             if (mVerboseLoggingEnabled) {
2947                 Log.d(TAG, "setSupportedFeatureSet to " + mSupportedFeatureSet);
2948             }
2949         }
2950     }
2951 
2952     /**
2953      * Get the current supported Wifi feature set.
2954      * @return supported Wifi feature set
2955      */
getSupportedFeatureSet()2956     public @NonNull BitSet getSupportedFeatureSet() {
2957         synchronized (mServiceApiLock) {
2958             return mSupportedFeatureSet;
2959         }
2960     }
2961 
2962     /**
2963      * Check if a band is supported as STA
2964      * @param band Wifi band
2965      * @return true if supported
2966      */
isBandSupportedForSta(@ifiScanner.WifiBand int band)2967     public boolean isBandSupportedForSta(@WifiScanner.WifiBand int band) {
2968         return (mBandsSupported.get() & band) != 0;
2969     }
2970 
setBandSupported(@ifiScanner.WifiBand int bands)2971     private void setBandSupported(@WifiScanner.WifiBand int bands) {
2972         mBandsSupported.set(bands);
2973         saveStaBandsToConfigStoreIfNecessary(bands);
2974         if (mVerboseLoggingEnabled) {
2975             Log.d(TAG, "setBandSupported 0x" + Long.toHexString(mBandsSupported.get()));
2976         }
2977     }
2978 
2979     /**
2980      * Get the current default Wifi network.
2981      * @return the default Wifi network
2982      */
getCurrentNetwork()2983     public Network getCurrentNetwork() {
2984         synchronized (mServiceApiLock) {
2985             return mCurrentNetwork;
2986         }
2987     }
2988 
2989     /**
2990      * Set the current default Wifi network. Called from ClientModeImpl.
2991      * @param network the default Wifi network
2992      */
setCurrentNetwork(Network network)2993     protected void setCurrentNetwork(Network network) {
2994         synchronized (mServiceApiLock) {
2995             mCurrentNetwork = network;
2996         }
2997     }
2998 
2999     /**
3000      * Get the current Wifi network connection info.
3001      * @return the default Wifi network connection info
3002      */
getConnectionInfo()3003     public @NonNull WifiInfo getConnectionInfo() {
3004         synchronized (mServiceApiLock) {
3005             return new WifiInfo(mCurrentConnectionInfo);
3006         }
3007     }
3008 
3009     /**
3010      * Update the current connection information.
3011      */
updateCurrentConnectionInfo()3012     public void updateCurrentConnectionInfo() {
3013         synchronized (mServiceApiLock) {
3014             mCurrentConnectionInfo = getPrimaryClientModeManager().getConnectionInfo();
3015         }
3016     }
3017 
3018     /**
3019      * Save the supported bands for STA from WiFi HAL to config store.
3020      * @param bands bands supported
3021      */
saveStaBandsToConfigStoreIfNecessary(int bands)3022     private void saveStaBandsToConfigStoreIfNecessary(int bands) {
3023         if (bands != getStaBandsFromConfigStore()) {
3024             mWifiInjector.getSettingsConfigStore().put(WIFI_NATIVE_SUPPORTED_STA_BANDS, bands);
3025             Log.i(TAG, "Supported STA bands is updated in config store: " + bands);
3026         }
3027     }
3028 
3029     /**
3030      * Get the supported STA bands from cache/config store
3031      * @return bands supported
3032      */
getStaBandsFromConfigStore()3033     private int getStaBandsFromConfigStore() {
3034         return mWifiInjector.getSettingsConfigStore().get(WIFI_NATIVE_SUPPORTED_STA_BANDS);
3035     }
3036 
3037     /**
3038      * Save the device mobility state when it updates. If the primary client mode manager is
3039      * non-null, pass the mobility state to clientModeImpl and update the RSSI polling
3040      * interval accordingly.
3041      */
setDeviceMobilityState(@eviceMobilityState int newState)3042     public void setDeviceMobilityState(@DeviceMobilityState int newState) {
3043         mDeviceMobilityState = newState;
3044         ClientModeManager cm = getPrimaryClientModeManagerNullable();
3045         if (cm != null) {
3046             cm.onDeviceMobilityStateUpdated(newState);
3047         }
3048     }
3049 
3050     /**
3051      * Get the current device mobility state
3052      */
getDeviceMobilityState()3053     public int getDeviceMobilityState() {
3054         return mDeviceMobilityState;
3055     }
3056 
3057     @VisibleForTesting
handleSatelliteModeChange()3058     public void handleSatelliteModeChange() {
3059         mSettingsStore.updateSatelliteModeTracker();
3060         mWifiController.sendMessage(WifiController.CMD_SATELLITE_MODE_CHANGED);
3061     }
3062 
3063     /**
3064      * Returns the number of multiple link devices (MLD) which are being operated.
3065      */
getCurrentMLDAp()3066     public int getCurrentMLDAp() {
3067         if (!SdkLevel.isAtLeastT()) {
3068             return 0;
3069         }
3070         int numberMLD = 0;
3071         for (SoftApManager manager : mSoftApManagers) {
3072             if (manager.isStarted() && manager.getSoftApModeConfiguration()
3073                     .getSoftApConfiguration().isIeee80211beEnabled()) {
3074                 if (manager.isBridgedMode() && !manager.isUsingMlo()) {
3075                     // Non MLO bridged mode, it occupies two MLD APs.
3076                     numberMLD += 2;
3077                 } else {
3078                     numberMLD++;
3079                 }
3080             }
3081         }
3082         return numberMLD;
3083     }
3084 }
3085