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