• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.wifi;
18 
19 import static android.net.wifi.WifiManager.IFACE_IP_MODE_LOCAL_ONLY;
20 import static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED;
21 import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED;
22 import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING;
23 import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED;
24 import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING;
25 import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN;
26 
27 import static com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_LOCAL_ONLY;
28 import static com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_PRIMARY;
29 import static com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_SCAN_ONLY;
30 import static com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_SECONDARY_LONG_LIVED;
31 import static com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_SECONDARY_TRANSIENT;
32 import static com.android.server.wifi.ActiveModeManager.ROLE_SOFTAP_TETHERED;
33 
34 import android.annotation.NonNull;
35 import android.annotation.Nullable;
36 import android.content.BroadcastReceiver;
37 import android.content.Context;
38 import android.content.Intent;
39 import android.content.IntentFilter;
40 import android.location.LocationManager;
41 import android.net.wifi.ISubsystemRestartCallback;
42 import android.net.wifi.IWifiConnectedNetworkScorer;
43 import android.net.wifi.SoftApCapability;
44 import android.net.wifi.SoftApConfiguration;
45 import android.net.wifi.WifiConfiguration;
46 import android.net.wifi.WifiManager;
47 import android.os.BatteryStatsManager;
48 import android.os.Build;
49 import android.os.Handler;
50 import android.os.IBinder;
51 import android.os.Looper;
52 import android.os.Message;
53 import android.os.Process;
54 import android.os.RemoteCallbackList;
55 import android.os.RemoteException;
56 import android.os.UserHandle;
57 import android.os.UserManager;
58 import android.os.WorkSource;
59 import android.telephony.TelephonyManager;
60 import android.text.TextUtils;
61 import android.util.ArraySet;
62 import android.util.Log;
63 import android.util.Pair;
64 
65 import com.android.internal.annotations.VisibleForTesting;
66 import com.android.internal.util.IState;
67 import com.android.internal.util.Preconditions;
68 import com.android.internal.util.Protocol;
69 import com.android.internal.util.State;
70 import com.android.internal.util.StateMachine;
71 import com.android.modules.utils.build.SdkLevel;
72 import com.android.server.wifi.ActiveModeManager.ClientConnectivityRole;
73 import com.android.server.wifi.ActiveModeManager.ClientInternetConnectivityRole;
74 import com.android.server.wifi.ActiveModeManager.ClientRole;
75 import com.android.server.wifi.ActiveModeManager.SoftApRole;
76 import com.android.server.wifi.util.WifiPermissionsUtil;
77 import com.android.wifi.resources.R;
78 
79 import java.io.FileDescriptor;
80 import java.io.PrintWriter;
81 import java.util.ArrayDeque;
82 import java.util.ArrayList;
83 import java.util.Collection;
84 import java.util.Collections;
85 import java.util.List;
86 import java.util.Objects;
87 import java.util.Set;
88 import java.util.concurrent.Executor;
89 import java.util.concurrent.atomic.AtomicInteger;
90 import java.util.stream.Collectors;
91 import java.util.stream.Stream;
92 
93 /**
94  * This class provides the implementation for different WiFi operating modes.
95  */
96 public class ActiveModeWarden {
97     private static final String TAG = "WifiActiveModeWarden";
98     private static final String STATE_MACHINE_EXITED_STATE_NAME = "STATE_MACHINE_EXITED";
99     public static final WorkSource INTERNAL_REQUESTOR_WS = new WorkSource(Process.WIFI_UID);
100 
101     // Holder for active mode managers
102     private final Set<ConcreteClientModeManager> mClientModeManagers = new ArraySet<>();
103     private final Set<SoftApManager> mSoftApManagers = new ArraySet<>();
104 
105     private final Set<ModeChangeCallback> mCallbacks = new ArraySet<>();
106     private final Set<PrimaryClientModeManagerChangedCallback> mPrimaryChangedCallbacks =
107             new ArraySet<>();
108     // DefaultModeManager used to service API calls when there are no active client mode managers.
109     private final DefaultClientModeManager mDefaultClientModeManager;
110     private final WifiInjector mWifiInjector;
111     private final Looper mLooper;
112     private final Handler mHandler;
113     private final Context mContext;
114     private final WifiDiagnostics mWifiDiagnostics;
115     private final WifiSettingsStore mSettingsStore;
116     private final FrameworkFacade mFacade;
117     private final WifiPermissionsUtil mWifiPermissionsUtil;
118     private final BatteryStatsManager mBatteryStatsManager;
119     private final ScanRequestProxy mScanRequestProxy;
120     private final WifiNative mWifiNative;
121     private final WifiController mWifiController;
122     private final Graveyard mGraveyard;
123     private final WifiMetrics mWifiMetrics;
124     private final ExternalScoreUpdateObserverProxy mExternalScoreUpdateObserverProxy;
125     private final DppManager mDppManager;
126     private final UserManager mUserManager;
127 
128     private WifiServiceImpl.SoftApCallbackInternal mSoftApCallback;
129     private WifiServiceImpl.SoftApCallbackInternal mLohsCallback;
130 
131     private final RemoteCallbackList<ISubsystemRestartCallback> mRestartCallbacks =
132             new RemoteCallbackList<>();
133 
134     private boolean mIsShuttingdown = false;
135     private boolean mVerboseLoggingEnabled = false;
136     /** Cache to store the external scorer for primary and secondary (MBB) client mode manager. */
137     @Nullable private Pair<IBinder, IWifiConnectedNetworkScorer> mClientModeManagerScorer;
138 
139     @Nullable
140     private ConcreteClientModeManager mLastPrimaryClientModeManager = null;
141 
142     @Nullable
143     private WorkSource mLastPrimaryClientModeManagerRequestorWs = null;
144     @Nullable
145     private WorkSource mLastScanOnlyClientModeManagerRequestorWs = null;
146 
147     /**
148      * One of  {@link WifiManager#WIFI_STATE_DISABLED},
149      * {@link WifiManager#WIFI_STATE_DISABLING},
150      * {@link WifiManager#WIFI_STATE_ENABLED},
151      * {@link WifiManager#WIFI_STATE_ENABLING},
152      * {@link WifiManager#WIFI_STATE_UNKNOWN}
153      */
154     private final AtomicInteger mWifiState = new AtomicInteger(WIFI_STATE_DISABLED);
155 
156     /**
157      * Method that allows the active ClientModeManager to set the wifi state that is
158      * retrieved by API calls. Only primary ClientModeManager should call this method when state
159      * changes
160      * @param newState new state to set, invalid states are ignored.
161      */
setWifiStateForApiCalls(int newState)162     public void setWifiStateForApiCalls(int newState) {
163         switch (newState) {
164             case WIFI_STATE_DISABLING:
165             case WIFI_STATE_DISABLED:
166             case WIFI_STATE_ENABLING:
167             case WIFI_STATE_ENABLED:
168             case WIFI_STATE_UNKNOWN:
169                 if (mVerboseLoggingEnabled) {
170                     Log.d(TAG, "setting wifi state to: " + newState);
171                 }
172                 mWifiState.set(newState);
173                 break;
174             default:
175                 Log.d(TAG, "attempted to set an invalid state: " + newState);
176                 break;
177         }
178     }
179 
getWifiStateName()180     private String getWifiStateName() {
181         switch (mWifiState.get()) {
182             case WIFI_STATE_DISABLING:
183                 return "disabling";
184             case WIFI_STATE_DISABLED:
185                 return "disabled";
186             case WIFI_STATE_ENABLING:
187                 return "enabling";
188             case WIFI_STATE_ENABLED:
189                 return "enabled";
190             case WIFI_STATE_UNKNOWN:
191                 return "unknown state";
192             default:
193                 return "[invalid state]";
194         }
195     }
196 
197     /**
198      * Method used by WifiServiceImpl to get the current state of Wifi for API calls.
199      * The Wifi state is a global state of the device, which equals to the state of the primary STA.
200      * This method must be thread safe.
201      */
getWifiState()202     public int getWifiState() {
203         return mWifiState.get();
204     }
205 
206     /**
207      * Called from WifiServiceImpl to register a callback for notifications from SoftApManager
208      */
registerSoftApCallback(@onNull WifiServiceImpl.SoftApCallbackInternal callback)209     public void registerSoftApCallback(@NonNull WifiServiceImpl.SoftApCallbackInternal callback) {
210         mSoftApCallback = callback;
211     }
212 
213     /**
214      * Called from WifiServiceImpl to register a callback for notifications from SoftApManager
215      * for local-only hotspot.
216      */
registerLohsCallback(@onNull WifiServiceImpl.SoftApCallbackInternal callback)217     public void registerLohsCallback(@NonNull WifiServiceImpl.SoftApCallbackInternal callback) {
218         mLohsCallback = callback;
219     }
220 
221     /**
222      * Callbacks for indicating any mode manager changes to the rest of the system.
223      */
224     public interface ModeChangeCallback {
225         /**
226          * Invoked when new mode manager is added.
227          *
228          * @param activeModeManager Instance of {@link ActiveModeManager}.
229          */
onActiveModeManagerAdded(@onNull ActiveModeManager activeModeManager)230         void onActiveModeManagerAdded(@NonNull ActiveModeManager activeModeManager);
231 
232         /**
233          * Invoked when a mode manager is removed.
234          *
235          * @param activeModeManager Instance of {@link ActiveModeManager}.
236          */
onActiveModeManagerRemoved(@onNull ActiveModeManager activeModeManager)237         void onActiveModeManagerRemoved(@NonNull ActiveModeManager activeModeManager);
238 
239         /**
240          * Invoked when an existing mode manager's role is changed.
241          *
242          * @param activeModeManager Instance of {@link ActiveModeManager}.
243          */
onActiveModeManagerRoleChanged(@onNull ActiveModeManager activeModeManager)244         void onActiveModeManagerRoleChanged(@NonNull ActiveModeManager activeModeManager);
245     }
246 
247     /** Called when the primary ClientModeManager changes. */
248     public interface PrimaryClientModeManagerChangedCallback {
249         /**
250          * Note: The current implementation for changing primary CMM is not atomic (due to setRole()
251          * needing to go through StateMachine, which is async). Thus, when the primary CMM changes,
252          * the sequence of calls looks like this:
253          * 1. onChange(prevPrimaryCmm, null)
254          * 2. onChange(null, newPrimaryCmm)
255          * Nevertheless, at run time, these two calls should occur in rapid succession.
256          *
257          * @param prevPrimaryClientModeManager the previous primary ClientModeManager, or null if
258          *                                     there was no previous primary (e.g. Wifi was off).
259          * @param newPrimaryClientModeManager the new primary ClientModeManager, or null if there is
260          *                                    no longer a primary (e.g. Wifi was turned off).
261          */
onChange( @ullable ConcreteClientModeManager prevPrimaryClientModeManager, @Nullable ConcreteClientModeManager newPrimaryClientModeManager)262         void onChange(
263                 @Nullable ConcreteClientModeManager prevPrimaryClientModeManager,
264                 @Nullable ConcreteClientModeManager newPrimaryClientModeManager);
265     }
266 
267     /**
268      * Keep stopped {@link ActiveModeManager} instances so that they can be dumped to aid debugging.
269      *
270      * TODO(b/160283853): Find a smarter way to evict old ActiveModeManagers
271      */
272     private static class Graveyard {
273         private static final int INSTANCES_TO_KEEP = 3;
274 
275         private final ArrayDeque<ConcreteClientModeManager> mClientModeManagers =
276                 new ArrayDeque<>();
277         private final ArrayDeque<SoftApManager> mSoftApManagers = new ArrayDeque<>();
278 
279         /**
280          * Add this stopped {@link ConcreteClientModeManager} to the graveyard, and evict the oldest
281          * ClientModeManager if the graveyard is full.
282          */
inter(ConcreteClientModeManager clientModeManager)283         void inter(ConcreteClientModeManager clientModeManager) {
284             if (mClientModeManagers.size() == INSTANCES_TO_KEEP) {
285                 mClientModeManagers.removeFirst();
286             }
287             mClientModeManagers.addLast(clientModeManager);
288         }
289 
290         /**
291          * Add this stopped {@link SoftApManager} to the graveyard, and evict the oldest
292          * SoftApManager if the graveyard is full.
293          */
inter(SoftApManager softApManager)294         void inter(SoftApManager softApManager) {
295             if (mSoftApManagers.size() == INSTANCES_TO_KEEP) {
296                 mSoftApManagers.removeFirst();
297             }
298             mSoftApManagers.addLast(softApManager);
299         }
300 
301         /** Dump the contents of the graveyard. */
dump(FileDescriptor fd, PrintWriter pw, String[] args)302         void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
303             pw.println("Dump of ActiveModeWarden.Graveyard");
304             pw.println("Stopped ClientModeManagers: " + mClientModeManagers.size() + " total");
305             for (ConcreteClientModeManager clientModeManager : mClientModeManagers) {
306                 clientModeManager.dump(fd, pw, args);
307             }
308             pw.println("Stopped SoftApManagers: " + mSoftApManagers.size() + " total");
309             for (SoftApManager softApManager : mSoftApManagers) {
310                 softApManager.dump(fd, pw, args);
311             }
312             pw.println();
313         }
314     }
315 
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)316     ActiveModeWarden(WifiInjector wifiInjector,
317             Looper looper,
318             WifiNative wifiNative,
319             DefaultClientModeManager defaultClientModeManager,
320             BatteryStatsManager batteryStatsManager,
321             WifiDiagnostics wifiDiagnostics,
322             Context context,
323             WifiSettingsStore settingsStore,
324             FrameworkFacade facade,
325             WifiPermissionsUtil wifiPermissionsUtil,
326             WifiMetrics wifiMetrics,
327             ExternalScoreUpdateObserverProxy externalScoreUpdateObserverProxy,
328             DppManager dppManager) {
329         mWifiInjector = wifiInjector;
330         mLooper = looper;
331         mHandler = new Handler(looper);
332         mContext = context;
333         mWifiDiagnostics = wifiDiagnostics;
334         mSettingsStore = settingsStore;
335         mFacade = facade;
336         mWifiPermissionsUtil = wifiPermissionsUtil;
337         mDefaultClientModeManager = defaultClientModeManager;
338         mBatteryStatsManager = batteryStatsManager;
339         mScanRequestProxy = wifiInjector.getScanRequestProxy();
340         mWifiNative = wifiNative;
341         mWifiMetrics = wifiMetrics;
342         mWifiController = new WifiController();
343         mExternalScoreUpdateObserverProxy = externalScoreUpdateObserverProxy;
344         mDppManager = dppManager;
345         mGraveyard = new Graveyard();
346         mUserManager = mWifiInjector.getUserManager();
347 
348         wifiNative.registerStatusListener(isReady -> {
349             if (!isReady && !mIsShuttingdown) {
350                 mHandler.post(() -> {
351                     Log.e(TAG, "One of the native daemons died. Triggering recovery");
352                     wifiDiagnostics.triggerBugReportDataCapture(
353                             WifiDiagnostics.REPORT_REASON_WIFINATIVE_FAILURE);
354 
355                     // immediately trigger SelfRecovery if we receive a notice about an
356                     // underlying daemon failure
357                     // Note: SelfRecovery has a circular dependency with ActiveModeWarden and is
358                     // instantiated after ActiveModeWarden, so use WifiInjector to get the instance
359                     // instead of directly passing in SelfRecovery in the constructor.
360                     mWifiInjector.getSelfRecovery().trigger(SelfRecovery.REASON_WIFINATIVE_FAILURE);
361                 });
362             }
363         });
364 
365         registerPrimaryClientModeManagerChangedCallback(
366                 (prevPrimaryClientModeManager, newPrimaryClientModeManager) -> {
367                     // TODO (b/181363901): We can always propagate the external scorer to all
368                     // ClientModeImpl instances. WifiScoreReport already handles skipping external
369                     // scorer notification for local only & restricted STA + STA use-cases. For MBB
370                     // use-case, we may want the external scorer to be notified.
371                     if (prevPrimaryClientModeManager != null) {
372                         prevPrimaryClientModeManager.clearWifiConnectedNetworkScorer();
373                     }
374                     if (newPrimaryClientModeManager != null && mClientModeManagerScorer != null) {
375                         newPrimaryClientModeManager.setWifiConnectedNetworkScorer(
376                                 mClientModeManagerScorer.first,
377                                 mClientModeManagerScorer.second);
378                     }
379                 });
380     }
381 
invokeOnAddedCallbacks(@onNull ActiveModeManager activeModeManager)382     private void invokeOnAddedCallbacks(@NonNull ActiveModeManager activeModeManager) {
383         if (mVerboseLoggingEnabled) {
384             Log.v(TAG, "ModeManager added " + activeModeManager);
385         }
386         for (ModeChangeCallback callback : mCallbacks) {
387             callback.onActiveModeManagerAdded(activeModeManager);
388         }
389     }
390 
invokeOnRemovedCallbacks(@onNull ActiveModeManager activeModeManager)391     private void invokeOnRemovedCallbacks(@NonNull ActiveModeManager activeModeManager) {
392         if (mVerboseLoggingEnabled) {
393             Log.v(TAG, "ModeManager removed " + activeModeManager);
394         }
395         for (ModeChangeCallback callback : mCallbacks) {
396             callback.onActiveModeManagerRemoved(activeModeManager);
397         }
398     }
399 
invokeOnRoleChangedCallbacks(@onNull ActiveModeManager activeModeManager)400     private void invokeOnRoleChangedCallbacks(@NonNull ActiveModeManager activeModeManager) {
401         if (mVerboseLoggingEnabled) {
402             Log.v(TAG, "ModeManager role changed " + activeModeManager);
403         }
404         for (ModeChangeCallback callback : mCallbacks) {
405             callback.onActiveModeManagerRoleChanged(activeModeManager);
406         }
407     }
408 
invokeOnPrimaryClientModeManagerChangedCallbacks( @ullable ConcreteClientModeManager prevPrimaryClientModeManager, @Nullable ConcreteClientModeManager newPrimaryClientModeManager)409     private void invokeOnPrimaryClientModeManagerChangedCallbacks(
410             @Nullable ConcreteClientModeManager prevPrimaryClientModeManager,
411             @Nullable ConcreteClientModeManager newPrimaryClientModeManager) {
412         if (mVerboseLoggingEnabled) {
413             Log.v(TAG, "Primary ClientModeManager changed from " + prevPrimaryClientModeManager
414                     + " to " + newPrimaryClientModeManager);
415         }
416         for (PrimaryClientModeManagerChangedCallback callback : mPrimaryChangedCallbacks) {
417             callback.onChange(prevPrimaryClientModeManager, newPrimaryClientModeManager);
418         }
419     }
420 
421     /**
422      * Enable verbose logging.
423      */
enableVerboseLogging(boolean verbose)424     public void enableVerboseLogging(boolean verbose) {
425         mVerboseLoggingEnabled = verbose;
426         for (ActiveModeManager modeManager : getActiveModeManagers()) {
427             modeManager.enableVerboseLogging(verbose);
428         }
429     }
430 
431     /**
432      * See {@link android.net.wifi.WifiManager#setWifiConnectedNetworkScorer(Executor,
433      * WifiManager.WifiConnectedNetworkScorer)}
434      */
setWifiConnectedNetworkScorer(IBinder binder, IWifiConnectedNetworkScorer scorer)435     public boolean setWifiConnectedNetworkScorer(IBinder binder,
436             IWifiConnectedNetworkScorer scorer) {
437         try {
438             scorer.onSetScoreUpdateObserver(mExternalScoreUpdateObserverProxy);
439         } catch (RemoteException e) {
440             Log.e(TAG, "Unable to set score update observer " + scorer, e);
441             return false;
442         }
443         mClientModeManagerScorer = Pair.create(binder, scorer);
444         return getPrimaryClientModeManager().setWifiConnectedNetworkScorer(binder, scorer);
445     }
446 
447     /**
448      * See {@link WifiManager#clearWifiConnectedNetworkScorer()}
449      */
clearWifiConnectedNetworkScorer()450     public void clearWifiConnectedNetworkScorer() {
451         mClientModeManagerScorer = null;
452         getPrimaryClientModeManager().clearWifiConnectedNetworkScorer();
453     }
454 
455     /**
456      * Register for mode change callbacks.
457      */
registerModeChangeCallback(@onNull ModeChangeCallback callback)458     public void registerModeChangeCallback(@NonNull ModeChangeCallback callback) {
459         mCallbacks.add(Objects.requireNonNull(callback));
460     }
461 
462     /**
463      * Unregister mode change callback.
464      */
unregisterModeChangeCallback(@onNull ModeChangeCallback callback)465     public void unregisterModeChangeCallback(@NonNull ModeChangeCallback callback) {
466         mCallbacks.remove(Objects.requireNonNull(callback));
467     }
468 
469     /** Register for primary ClientModeManager changed callbacks. */
registerPrimaryClientModeManagerChangedCallback( @onNull PrimaryClientModeManagerChangedCallback callback)470     public void registerPrimaryClientModeManagerChangedCallback(
471             @NonNull PrimaryClientModeManagerChangedCallback callback) {
472         mPrimaryChangedCallbacks.add(Objects.requireNonNull(callback));
473         // If there is already a primary CMM when registering, send a callback with the info.
474         ConcreteClientModeManager cm = getPrimaryClientModeManagerNullable();
475         if (cm != null) callback.onChange(null, cm);
476     }
477 
478     /** Unregister for primary ClientModeManager changed callbacks. */
unregisterPrimaryClientModeManagerChangedCallback( @onNull PrimaryClientModeManagerChangedCallback callback)479     public void unregisterPrimaryClientModeManagerChangedCallback(
480             @NonNull PrimaryClientModeManagerChangedCallback callback) {
481         mPrimaryChangedCallbacks.remove(Objects.requireNonNull(callback));
482     }
483 
484     /**
485      * Notify that device is shutting down
486      * Keep it simple and don't add collection access codes
487      * to avoid concurrentModificationException when it is directly called from a different thread
488      */
notifyShuttingDown()489     public void notifyShuttingDown() {
490         mIsShuttingdown = true;
491     }
492 
493     /**
494      * @return Returns whether we can create more client mode managers or not.
495      */
canRequestMoreClientModeManagersInRole(@onNull WorkSource requestorWs, @NonNull ClientRole clientRole, boolean didUserApprove)496     public boolean canRequestMoreClientModeManagersInRole(@NonNull WorkSource requestorWs,
497             @NonNull ClientRole clientRole, boolean didUserApprove) {
498         WorkSource ifCreatorWs = new WorkSource(requestorWs);
499         if (didUserApprove) {
500             // If user select to connect from the UI, promote the priority
501             ifCreatorWs.add(mFacade.getSettingsWorkSource(mContext));
502         }
503         if (!mWifiNative.isItPossibleToCreateStaIface(ifCreatorWs)) {
504             return false;
505         }
506         if (clientRole == ROLE_CLIENT_LOCAL_ONLY) {
507             if (!mContext.getResources().getBoolean(
508                     R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled)) {
509                 return false;
510             }
511             final int uid = requestorWs.getUid(0);
512             final String packageName = requestorWs.getPackageName(0);
513             // For peer to peer use-case, only allow secondary STA if the app is targeting S SDK
514             // or is a system app to provide backward compatibility.
515             return mWifiPermissionsUtil.isSystem(packageName, uid)
516                     || !mWifiPermissionsUtil.isTargetSdkLessThan(
517                             packageName, Build.VERSION_CODES.S, uid);
518         }
519         if (clientRole == ROLE_CLIENT_SECONDARY_TRANSIENT) {
520             return mContext.getResources().getBoolean(
521                     R.bool.config_wifiMultiStaNetworkSwitchingMakeBeforeBreakEnabled);
522         }
523         if (clientRole == ROLE_CLIENT_SECONDARY_LONG_LIVED) {
524             return mContext.getResources().getBoolean(
525                     R.bool.config_wifiMultiStaRestrictedConcurrencyEnabled)
526                     || mContext.getResources().getBoolean(
527                     R.bool.config_wifiMultiStaMultiInternetConcurrencyEnabled);
528         }
529         Log.e(TAG, "Unrecognized role=" + clientRole);
530         return false;
531     }
532 
533     /**
534      * @return Returns whether we can create more SoftAp managers or not.
535      */
canRequestMoreSoftApManagers(@onNull WorkSource requestorWs)536     public boolean canRequestMoreSoftApManagers(@NonNull WorkSource requestorWs) {
537         return mWifiNative.isItPossibleToCreateApIface(requestorWs);
538     }
539 
540     /**
541      * @return Returns whether the device can support at least one concurrent client mode manager &
542      * softap manager.
543      */
isStaApConcurrencySupported()544     public boolean isStaApConcurrencySupported() {
545         return mWifiNative.isStaApConcurrencySupported();
546     }
547 
548     /**
549      * @return Returns whether the device can support at least two concurrent client mode managers
550      * and the local only use-case is enabled.
551      */
isStaStaConcurrencySupportedForLocalOnlyConnections()552     public boolean isStaStaConcurrencySupportedForLocalOnlyConnections() {
553         return mWifiNative.isStaStaConcurrencySupported()
554                 && mContext.getResources().getBoolean(
555                         R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled);
556     }
557 
558     /**
559      * @return Returns whether the device can support at least two concurrent client mode managers
560      * and the mbb wifi switching is enabled.
561      */
isStaStaConcurrencySupportedForMbb()562     public boolean isStaStaConcurrencySupportedForMbb() {
563         return mWifiNative.isStaStaConcurrencySupported()
564                 && mContext.getResources().getBoolean(
565                         R.bool.config_wifiMultiStaNetworkSwitchingMakeBeforeBreakEnabled);
566     }
567 
568     /**
569      * @return Returns whether the device can support at least two concurrent client mode managers
570      * and the restricted use-case is enabled.
571      */
isStaStaConcurrencySupportedForRestrictedConnections()572     public boolean isStaStaConcurrencySupportedForRestrictedConnections() {
573         return mWifiNative.isStaStaConcurrencySupported()
574                 && mContext.getResources().getBoolean(
575                         R.bool.config_wifiMultiStaRestrictedConcurrencyEnabled);
576     }
577 
578     /**
579      * @return Returns whether the device can support at least two concurrent client mode managers
580      * and the multi internet use-case is enabled.
581      */
isStaStaConcurrencySupportedForMultiInternet()582     public boolean isStaStaConcurrencySupportedForMultiInternet() {
583         return mWifiNative.isStaStaConcurrencySupported()
584                 && mContext.getResources().getBoolean(
585                         R.bool.config_wifiMultiStaMultiInternetConcurrencyEnabled);
586     }
587 
588     /** Begin listening to broadcasts and start the internal state machine. */
start()589     public void start() {
590         mContext.registerReceiver(new BroadcastReceiver() {
591             @Override
592             public void onReceive(Context context, Intent intent) {
593                 // Location mode has been toggled...  trigger with the scan change
594                 // update to make sure we are in the correct mode
595                 scanAlwaysModeChanged();
596             }
597         }, new IntentFilter(LocationManager.MODE_CHANGED_ACTION));
598         mContext.registerReceiver(new BroadcastReceiver() {
599             @Override
600             public void onReceive(Context context, Intent intent) {
601                 boolean airplaneModeUpdated = mSettingsStore.updateAirplaneModeTracker();
602                 boolean userRestrictionSet =
603                         SdkLevel.isAtLeastT() && mUserManager.hasUserRestrictionForUser(
604                                 UserManager.DISALLOW_CHANGE_WIFI_STATE,
605                                 UserHandle.getUserHandleForUid(Process.SYSTEM_UID));
606                 if (!userRestrictionSet && airplaneModeUpdated) {
607                     mSettingsStore.handleAirplaneModeToggled();
608                     airplaneModeToggled();
609                 }
610             }
611         }, new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
612         mContext.registerReceiver(new BroadcastReceiver() {
613             @Override
614             public void onReceive(Context context, Intent intent) {
615                 boolean emergencyMode =
616                         intent.getBooleanExtra(TelephonyManager.EXTRA_PHONE_IN_ECM_STATE, false);
617                 emergencyCallbackModeChanged(emergencyMode);
618             }
619         }, new IntentFilter(TelephonyManager.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED));
620         boolean trackEmergencyCallState = mContext.getResources().getBoolean(
621                 R.bool.config_wifi_turn_off_during_emergency_call);
622         if (trackEmergencyCallState) {
623             mContext.registerReceiver(new BroadcastReceiver() {
624                 @Override
625                 public void onReceive(Context context, Intent intent) {
626                     boolean inCall = intent.getBooleanExtra(
627                             TelephonyManager.EXTRA_PHONE_IN_EMERGENCY_CALL, false);
628                     emergencyCallStateChanged(inCall);
629                 }
630             }, new IntentFilter(TelephonyManager.ACTION_EMERGENCY_CALL_STATE_CHANGED));
631         }
632 
633         mWifiController.start();
634     }
635 
636     /** Disable Wifi for recovery purposes. */
recoveryDisableWifi()637     public void recoveryDisableWifi() {
638         mWifiController.sendMessage(WifiController.CMD_RECOVERY_DISABLE_WIFI);
639     }
640 
641     /**
642      * Restart Wifi for recovery purposes.
643      * @param reason One of {@link SelfRecovery.RecoveryReason}
644      */
recoveryRestartWifi(@elfRecovery.RecoveryReason int reason, boolean requestBugReport)645     public void recoveryRestartWifi(@SelfRecovery.RecoveryReason int reason,
646             boolean requestBugReport) {
647         mWifiController.sendMessage(WifiController.CMD_RECOVERY_RESTART_WIFI, reason,
648                 requestBugReport ? 1 : 0, SelfRecovery.getRecoveryReasonAsString(reason));
649     }
650 
651     /**
652      * register a callback to monitor the progress of Wi-Fi subsystem operation (started/finished)
653      * - started via {@link #recoveryRestartWifi(int, String, boolean)}.
654      */
registerSubsystemRestartCallback(ISubsystemRestartCallback callback)655     public boolean registerSubsystemRestartCallback(ISubsystemRestartCallback callback) {
656         return mRestartCallbacks.register(callback);
657     }
658 
659     /**
660      * unregister a callback to monitor the progress of Wi-Fi subsystem operation (started/finished)
661      * - started via {@link #recoveryRestartWifi(int, String, boolean)}. Callback is registered via
662      * {@link #registerSubsystemRestartCallback(ISubsystemRestartCallback)}.
663      */
unregisterSubsystemRestartCallback(ISubsystemRestartCallback callback)664     public boolean unregisterSubsystemRestartCallback(ISubsystemRestartCallback callback) {
665         return mRestartCallbacks.unregister(callback);
666     }
667 
668     /** Wifi has been toggled. */
wifiToggled(WorkSource requestorWs)669     public void wifiToggled(WorkSource requestorWs) {
670         mWifiController.sendMessage(WifiController.CMD_WIFI_TOGGLED, requestorWs);
671     }
672 
673     /** Airplane Mode has been toggled. */
airplaneModeToggled()674     public void airplaneModeToggled() {
675         mWifiController.sendMessage(WifiController.CMD_AIRPLANE_TOGGLED);
676     }
677 
678     /** Starts SoftAp. */
startSoftAp(SoftApModeConfiguration softApConfig, WorkSource requestorWs)679     public void startSoftAp(SoftApModeConfiguration softApConfig, WorkSource requestorWs) {
680         mWifiController.sendMessage(WifiController.CMD_SET_AP, 1, 0,
681                 Pair.create(softApConfig, requestorWs));
682     }
683 
684     /** Stop SoftAp. */
stopSoftAp(int mode)685     public void stopSoftAp(int mode) {
686         mWifiController.sendMessage(WifiController.CMD_SET_AP, 0, mode);
687     }
688 
689     /** Update SoftAp Capability. */
updateSoftApCapability(SoftApCapability capability, int ipMode)690     public void updateSoftApCapability(SoftApCapability capability, int ipMode) {
691         mWifiController.sendMessage(WifiController.CMD_UPDATE_AP_CAPABILITY, ipMode, 0, capability);
692     }
693 
694     /** Update SoftAp Configuration. */
updateSoftApConfiguration(SoftApConfiguration config)695     public void updateSoftApConfiguration(SoftApConfiguration config) {
696         mWifiController.sendMessage(WifiController.CMD_UPDATE_AP_CONFIG, config);
697     }
698 
699     /** Emergency Callback Mode has changed. */
emergencyCallbackModeChanged(boolean isInEmergencyCallbackMode)700     public void emergencyCallbackModeChanged(boolean isInEmergencyCallbackMode) {
701         mWifiController.sendMessage(
702                 WifiController.CMD_EMERGENCY_MODE_CHANGED, isInEmergencyCallbackMode ? 1 : 0);
703     }
704 
705     /** Emergency Call state has changed. */
emergencyCallStateChanged(boolean isInEmergencyCall)706     public void emergencyCallStateChanged(boolean isInEmergencyCall) {
707         mWifiController.sendMessage(
708                 WifiController.CMD_EMERGENCY_CALL_STATE_CHANGED, isInEmergencyCall ? 1 : 0);
709     }
710 
711     /** Scan always mode has changed. */
scanAlwaysModeChanged()712     public void scanAlwaysModeChanged() {
713         mWifiController.sendMessage(
714                 WifiController.CMD_SCAN_ALWAYS_MODE_CHANGED,
715                 // Scan only mode change is not considered a direct user interaction since user
716                 // is not explicitly turning on wifi scanning (side-effect of location toggle).
717                 // So, use the lowest priority internal requestor worksource to ensure that this
718                 // is treated with the lowest priority.
719                 INTERNAL_REQUESTOR_WS);
720     }
721 
722     /** emergency scan progress indication. */
setEmergencyScanRequestInProgress(boolean inProgress)723     public void setEmergencyScanRequestInProgress(boolean inProgress) {
724         mWifiController.sendMessage(
725                 WifiController.CMD_EMERGENCY_SCAN_STATE_CHANGED,
726                 inProgress ? 1 : 0, 0,
727                 // Emergency scans should have the highest priority, so use settings worksource.
728                 mFacade.getSettingsWorkSource(mContext));
729     }
730 
731     /**
732      * Listener to request a ModeManager instance for a particular operation.
733      */
734     public interface ExternalClientModeManagerRequestListener {
735         /**
736          * Returns an instance of ClientModeManager or null if the request failed (when wifi is
737          * off).
738          */
onAnswer(@ullable ClientModeManager modeManager)739         void onAnswer(@Nullable ClientModeManager modeManager);
740     }
741 
742     private static class AdditionalClientModeManagerRequestInfo {
743         @NonNull public final ExternalClientModeManagerRequestListener listener;
744         @NonNull public final WorkSource requestorWs;
745         @NonNull public final ClientConnectivityRole clientRole;
746         @NonNull public final String ssid;
747         @Nullable public final String bssid;
748         public final boolean didUserApprove;
749 
AdditionalClientModeManagerRequestInfo( @onNull ExternalClientModeManagerRequestListener listener, @NonNull WorkSource requestorWs, @NonNull ClientConnectivityRole clientRole, @NonNull String ssid, @Nullable String bssid, boolean didUserApprove)750         AdditionalClientModeManagerRequestInfo(
751                 @NonNull ExternalClientModeManagerRequestListener listener,
752                 @NonNull WorkSource requestorWs,
753                 @NonNull ClientConnectivityRole clientRole,
754                 @NonNull String ssid,
755                 // For some use-cases, bssid is selected by firmware.
756                 @Nullable String bssid,
757                 boolean didUserApprove) {
758             this.listener = listener;
759             this.requestorWs = requestorWs;
760             this.clientRole = clientRole;
761             this.ssid = ssid;
762             this.bssid = bssid;
763             this.didUserApprove = didUserApprove;
764 
765         }
766     }
767 
768     /**
769      * Request a local only client manager.
770      * @param listener used to receive the requested ClientModeManager. Will receive:
771      *                 1. null - if Wifi is toggled off
772      *                 2. The primary ClientModeManager - if a new ClientModeManager cannot be
773      *                    created.
774      *                 3. The new ClientModeManager - if it was created successfully.
775      * @param requestorWs the WorkSource for this request
776      * @param didUserApprove if user explicitly approve on this request
777      */
requestLocalOnlyClientModeManager( @onNull ExternalClientModeManagerRequestListener listener, @NonNull WorkSource requestorWs, @NonNull String ssid, @NonNull String bssid, boolean didUserApprove)778     public void requestLocalOnlyClientModeManager(
779             @NonNull ExternalClientModeManagerRequestListener listener,
780             @NonNull WorkSource requestorWs, @NonNull String ssid, @NonNull String bssid,
781             boolean didUserApprove) {
782         mWifiController.sendMessage(
783                 WifiController.CMD_REQUEST_ADDITIONAL_CLIENT_MODE_MANAGER,
784                 new AdditionalClientModeManagerRequestInfo(
785                         Objects.requireNonNull(listener), Objects.requireNonNull(requestorWs),
786                         ROLE_CLIENT_LOCAL_ONLY, ssid, bssid, didUserApprove));
787     }
788 
789     /**
790      * Request a secondary long lived client manager.
791      *
792      * @param listener used to receive the requested ClientModeManager. Will receive:
793      *                 1. null - if Wifi is toggled off
794      *                 2. The primary ClientModeManager - if a new ClientModeManager cannot be
795      *                    created.
796      *                 3. The new ClientModeManager - if it was created successfully.
797      * @param requestorWs the WorkSource for this request
798      */
requestSecondaryLongLivedClientModeManager( @onNull ExternalClientModeManagerRequestListener listener, @NonNull WorkSource requestorWs, @NonNull String ssid, @Nullable String bssid)799     public void requestSecondaryLongLivedClientModeManager(
800             @NonNull ExternalClientModeManagerRequestListener listener,
801             @NonNull WorkSource requestorWs, @NonNull String ssid, @Nullable String bssid) {
802         mWifiController.sendMessage(
803                 WifiController.CMD_REQUEST_ADDITIONAL_CLIENT_MODE_MANAGER,
804                 new AdditionalClientModeManagerRequestInfo(
805                         Objects.requireNonNull(listener), Objects.requireNonNull(requestorWs),
806                         ROLE_CLIENT_SECONDARY_LONG_LIVED, ssid, bssid, false));
807     }
808 
809     /**
810      * Request a secondary transient client manager.
811      *
812      * @param listener used to receive the requested ClientModeManager. Will receive:
813      *                 1. null - if Wifi is toggled off.
814      *                 2. An existing secondary transient ClientModeManager - if it already exists.
815      *                 3. A new secondary transient ClientModeManager - if one doesn't exist and one
816      *                    was created successfully.
817      *                 4. The primary ClientModeManager - if a new ClientModeManager cannot be
818      *                    created.
819      * @param requestorWs the WorkSource for this request
820      */
requestSecondaryTransientClientModeManager( @onNull ExternalClientModeManagerRequestListener listener, @NonNull WorkSource requestorWs, @NonNull String ssid, @Nullable String bssid)821     public void requestSecondaryTransientClientModeManager(
822             @NonNull ExternalClientModeManagerRequestListener listener,
823             @NonNull WorkSource requestorWs, @NonNull String ssid, @Nullable String bssid) {
824         mWifiController.sendMessage(
825                 WifiController.CMD_REQUEST_ADDITIONAL_CLIENT_MODE_MANAGER,
826                 new AdditionalClientModeManagerRequestInfo(
827                         Objects.requireNonNull(listener), Objects.requireNonNull(requestorWs),
828                         ROLE_CLIENT_SECONDARY_TRANSIENT, ssid, bssid, false));
829     }
830 
831     /**
832      * Checks if a CMM can be started for MBB.
833      */
canRequestSecondaryTransientClientModeManager()834     public boolean canRequestSecondaryTransientClientModeManager() {
835         return canRequestMoreClientModeManagersInRole(INTERNAL_REQUESTOR_WS,
836                 ROLE_CLIENT_SECONDARY_TRANSIENT, false);
837     }
838 
839     /**
840      * Remove the provided client manager.
841      */
removeClientModeManager(ClientModeManager clientModeManager)842     public void removeClientModeManager(ClientModeManager clientModeManager) {
843         mWifiController.sendMessage(
844                 WifiController.CMD_REMOVE_ADDITIONAL_CLIENT_MODE_MANAGER, clientModeManager);
845     }
846 
847     /**
848      * Check whether we have a primary client mode manager (indicates wifi toggle on).
849      */
hasPrimaryClientModeManager()850     public boolean hasPrimaryClientModeManager() {
851         return getClientModeManagerInRole(ROLE_CLIENT_PRIMARY) != null;
852     }
853 
854     /**
855      * Checks whether there exists a primary or scan only mode manager.
856      * @return
857      */
hasPrimaryOrScanOnlyModeManager()858     private boolean hasPrimaryOrScanOnlyModeManager() {
859         return getClientModeManagerInRole(ROLE_CLIENT_PRIMARY) != null
860                 || getClientModeManagerInRole(ROLE_CLIENT_SCAN_ONLY) != null
861                 || getClientModeManagerTransitioningIntoRole(ROLE_CLIENT_PRIMARY) != null
862                 || getClientModeManagerTransitioningIntoRole(ROLE_CLIENT_SCAN_ONLY) != null;
863     }
864 
865     /**
866      * Returns primary client mode manager if any, else returns null
867      * This mode manager can be the default route on the device & will handle all external API
868      * calls.
869      * @return Instance of {@link ConcreteClientModeManager} or null.
870      */
871     @Nullable
getPrimaryClientModeManagerNullable()872     public ConcreteClientModeManager getPrimaryClientModeManagerNullable() {
873         return getClientModeManagerInRole(ROLE_CLIENT_PRIMARY);
874     }
875 
876     /**
877      * Returns primary client mode manager if any, else returns an instance of
878      * {@link ClientModeManager}.
879      * This mode manager can be the default route on the device & will handle all external API
880      * calls.
881      * @return Instance of {@link ClientModeManager}.
882      */
883     @NonNull
getPrimaryClientModeManager()884     public ClientModeManager getPrimaryClientModeManager() {
885         ClientModeManager cm = getPrimaryClientModeManagerNullable();
886         if (cm != null) return cm;
887         // If there is no primary client manager, return the default one.
888         return mDefaultClientModeManager;
889     }
890 
891     /**
892      * Returns all instances of ClientModeManager in
893      * {@link ActiveModeManager.ClientInternetConnectivityRole} roles.
894      * @return List of {@link ClientModeManager}.
895      */
896     @NonNull
getInternetConnectivityClientModeManagers()897     public List<ClientModeManager> getInternetConnectivityClientModeManagers() {
898         List<ClientModeManager> modeManagers = new ArrayList<>();
899         for (ConcreteClientModeManager manager : mClientModeManagers) {
900             if (manager.getRole() instanceof ClientInternetConnectivityRole) {
901                 modeManagers.add(manager);
902             }
903         }
904         return modeManagers;
905     }
906 
907     /** Stop all secondary transient ClientModeManagers. */
stopAllClientModeManagersInRole(ClientRole role)908     public void stopAllClientModeManagersInRole(ClientRole role) {
909         // there should only be at most one Make Before Break CMM, but check all of them to be safe.
910         for (ConcreteClientModeManager manager : mClientModeManagers) {
911             if (manager.getRole() == role) {
912                 stopAdditionalClientModeManager(manager);
913             }
914         }
915     }
916 
917     @NonNull
getClientModeManagers()918     public List<ClientModeManager> getClientModeManagers() {
919         return new ArrayList<>(mClientModeManagers);
920     }
921 
922     /**
923      * Returns scan only client mode manager, if any.
924      * This mode manager will only allow scanning.
925      * @return Instance of {@link ClientModeManager} or null if none present.
926      */
927     @Nullable
getScanOnlyClientModeManager()928     public ClientModeManager getScanOnlyClientModeManager() {
929         return getClientModeManagerInRole(ROLE_CLIENT_SCAN_ONLY);
930     }
931 
932     /**
933      * Returns tethered softap manager, if any.
934      * @return Instance of {@link SoftApManager} or null if none present.
935      */
936     @Nullable
getTetheredSoftApManager()937     public SoftApManager getTetheredSoftApManager() {
938         return getSoftApManagerInRole(ROLE_SOFTAP_TETHERED);
939     }
940 
941     /**
942      * Returns LOHS softap manager, if any.
943      * @return Instance of {@link SoftApManager} or null if none present.
944      */
945     @Nullable
getLocalOnlySoftApManager()946     public SoftApManager getLocalOnlySoftApManager() {
947         return getSoftApManagerInRole(ActiveModeManager.ROLE_SOFTAP_LOCAL_ONLY);
948     }
949 
hasAnyModeManager()950     private boolean hasAnyModeManager() {
951         return !mClientModeManagers.isEmpty() || !mSoftApManagers.isEmpty();
952     }
953 
hasAnyClientModeManager()954     private boolean hasAnyClientModeManager() {
955         return !mClientModeManagers.isEmpty();
956     }
957 
hasAnyClientModeManagerInConnectivityRole()958     private boolean hasAnyClientModeManagerInConnectivityRole() {
959         for (ConcreteClientModeManager manager : mClientModeManagers) {
960             if (manager.getRole() instanceof ClientConnectivityRole) return true;
961         }
962         return false;
963     }
964 
hasAnySoftApManager()965     private boolean hasAnySoftApManager() {
966         return !mSoftApManagers.isEmpty();
967     }
968 
969     /**
970      * @return true if all the client mode managers are in scan only role,
971      * false if there are no client mode managers present or if any of them are not in scan only
972      * role.
973      */
areAllClientModeManagersInScanOnlyRole()974     private boolean areAllClientModeManagersInScanOnlyRole() {
975         if (mClientModeManagers.isEmpty()) return false;
976         for (ConcreteClientModeManager manager : mClientModeManagers) {
977             if (manager.getRole() != ROLE_CLIENT_SCAN_ONLY) return false;
978         }
979         return true;
980     }
981 
982     /** Get any client mode manager in the given role, or null if none was found. */
983     @Nullable
getClientModeManagerInRole(ClientRole role)984     public ConcreteClientModeManager getClientModeManagerInRole(ClientRole role) {
985         for (ConcreteClientModeManager manager : mClientModeManagers) {
986             if (manager.getRole() == role) return manager;
987         }
988         return null;
989     }
990 
991     @Nullable
getClientModeManagerTransitioningIntoRole(ClientRole role)992     private ConcreteClientModeManager getClientModeManagerTransitioningIntoRole(ClientRole role) {
993         for (ConcreteClientModeManager manager : mClientModeManagers) {
994             if (manager.getTargetRole() == role) return manager;
995         }
996         return null;
997     }
998 
999     /** Get all client mode managers in the specified roles. */
1000     @NonNull
getClientModeManagersInRoles(ClientRole... roles)1001     public List<ConcreteClientModeManager> getClientModeManagersInRoles(ClientRole... roles) {
1002         Set<ClientRole> rolesSet = Set.of(roles);
1003         List<ConcreteClientModeManager> result = new ArrayList<>();
1004         for (ConcreteClientModeManager manager : mClientModeManagers) {
1005             ClientRole role = manager.getRole();
1006             if (role != null && rolesSet.contains(role)) {
1007                 result.add(manager);
1008             }
1009         }
1010         return result;
1011     }
1012 
1013     @Nullable
getSoftApManagerInRole(SoftApRole role)1014     private SoftApManager getSoftApManagerInRole(SoftApRole role) {
1015         for (SoftApManager manager : mSoftApManagers) {
1016             if (manager.getRole() == role) return manager;
1017         }
1018         return null;
1019     }
1020 
getRoleForSoftApIpMode(int ipMode)1021     private SoftApRole getRoleForSoftApIpMode(int ipMode) {
1022         return ipMode == IFACE_IP_MODE_TETHERED
1023                 ? ROLE_SOFTAP_TETHERED
1024                 : ActiveModeManager.ROLE_SOFTAP_LOCAL_ONLY;
1025     }
1026 
1027     /**
1028      * Method to enable soft ap for wifi hotspot.
1029      *
1030      * The supplied SoftApModeConfiguration includes the target softap WifiConfiguration (or null if
1031      * the persisted config is to be used) and the target operating mode (ex,
1032      * {@link WifiManager#IFACE_IP_MODE_TETHERED} {@link WifiManager#IFACE_IP_MODE_LOCAL_ONLY}).
1033      *
1034      * @param softApConfig SoftApModeConfiguration for the hostapd softap
1035      */
startSoftApModeManager( @onNull SoftApModeConfiguration softApConfig, @NonNull WorkSource requestorWs)1036     private void startSoftApModeManager(
1037             @NonNull SoftApModeConfiguration softApConfig, @NonNull WorkSource requestorWs) {
1038         Log.d(TAG, "Starting SoftApModeManager config = " + softApConfig.getSoftApConfiguration());
1039         Preconditions.checkState(softApConfig.getTargetMode() == IFACE_IP_MODE_LOCAL_ONLY
1040                 || softApConfig.getTargetMode() == IFACE_IP_MODE_TETHERED);
1041 
1042         WifiServiceImpl.SoftApCallbackInternal callback =
1043                 softApConfig.getTargetMode() == IFACE_IP_MODE_LOCAL_ONLY
1044                         ? mLohsCallback : mSoftApCallback;
1045         SoftApManager manager = mWifiInjector.makeSoftApManager(
1046                 new SoftApListener(), callback, softApConfig, requestorWs,
1047                 getRoleForSoftApIpMode(softApConfig.getTargetMode()), mVerboseLoggingEnabled);
1048         mSoftApManagers.add(manager);
1049     }
1050 
1051     /**
1052      * Method to stop all soft ap for the specified mode.
1053      *
1054      * This method will stop any active softAp mode managers.
1055      *
1056      * @param ipMode the operating mode of APs to bring down (ex,
1057      *             {@link WifiManager#IFACE_IP_MODE_TETHERED} or
1058      *             {@link WifiManager#IFACE_IP_MODE_LOCAL_ONLY}).
1059      *             Use {@link WifiManager#IFACE_IP_MODE_UNSPECIFIED} to stop all APs.
1060      */
stopSoftApModeManagers(int ipMode)1061     private void stopSoftApModeManagers(int ipMode) {
1062         Log.d(TAG, "Shutting down all softap mode managers in mode " + ipMode);
1063         for (SoftApManager softApManager : mSoftApManagers) {
1064             if (ipMode == WifiManager.IFACE_IP_MODE_UNSPECIFIED
1065                     || getRoleForSoftApIpMode(ipMode) == softApManager.getRole()) {
1066                 softApManager.stop();
1067             }
1068         }
1069     }
1070 
updateCapabilityToSoftApModeManager(SoftApCapability capability, int ipMode)1071     private void updateCapabilityToSoftApModeManager(SoftApCapability capability, int ipMode) {
1072         for (SoftApManager softApManager : mSoftApManagers) {
1073             if (ipMode == softApManager.getSoftApModeConfiguration().getTargetMode()) {
1074                 softApManager.updateCapability(capability);
1075             }
1076         }
1077     }
1078 
updateConfigurationToSoftApModeManager(SoftApConfiguration config)1079     private void updateConfigurationToSoftApModeManager(SoftApConfiguration config) {
1080         for (SoftApManager softApManager : mSoftApManagers) {
1081             softApManager.updateConfiguration(config);
1082         }
1083     }
1084 
1085     /**
1086      * Method to enable a new primary client mode manager in scan only mode.
1087      */
startScanOnlyClientModeManager(WorkSource requestorWs)1088     private boolean startScanOnlyClientModeManager(WorkSource requestorWs) {
1089         Log.d(TAG, "Starting primary ClientModeManager in scan only mode");
1090         ConcreteClientModeManager manager = mWifiInjector.makeClientModeManager(
1091                 new ClientListener(), requestorWs, ROLE_CLIENT_SCAN_ONLY, mVerboseLoggingEnabled);
1092         mClientModeManagers.add(manager);
1093         mLastScanOnlyClientModeManagerRequestorWs = requestorWs;
1094         return true;
1095     }
1096 
1097     /**
1098      * Method to enable a new primary client mode manager in connect mode.
1099      */
startPrimaryClientModeManager(WorkSource requestorWs)1100     private boolean startPrimaryClientModeManager(WorkSource requestorWs) {
1101         Log.d(TAG, "Starting primary ClientModeManager in connect mode");
1102         ConcreteClientModeManager manager = mWifiInjector.makeClientModeManager(
1103                 new ClientListener(), requestorWs, ROLE_CLIENT_PRIMARY, mVerboseLoggingEnabled);
1104         mClientModeManagers.add(manager);
1105         mLastPrimaryClientModeManagerRequestorWs = requestorWs;
1106         return true;
1107     }
1108 
1109     /**
1110      * Method to enable a new primary client mode manager.
1111      */
startPrimaryOrScanOnlyClientModeManager(WorkSource requestorWs)1112     private boolean startPrimaryOrScanOnlyClientModeManager(WorkSource requestorWs) {
1113         ActiveModeManager.ClientRole role = getRoleForPrimaryOrScanOnlyClientModeManager();
1114         if (role == ROLE_CLIENT_PRIMARY) {
1115             return startPrimaryClientModeManager(requestorWs);
1116         } else if (role == ROLE_CLIENT_SCAN_ONLY) {
1117             return startScanOnlyClientModeManager(requestorWs);
1118         } else {
1119             return false;
1120         }
1121     }
1122 
1123     /**
1124      * Method to stop all client mode mangers.
1125      */
stopAllClientModeManagers()1126     private void stopAllClientModeManagers() {
1127         Log.d(TAG, "Shutting down all client mode managers");
1128         for (ConcreteClientModeManager clientModeManager : mClientModeManagers) {
1129             clientModeManager.stop();
1130         }
1131     }
1132 
1133     /**
1134      * Method to switch all primary client mode manager mode of operation to ScanOnly mode.
1135      */
switchAllPrimaryClientModeManagersToScanOnlyMode(@onNull WorkSource requestorWs)1136     private void switchAllPrimaryClientModeManagersToScanOnlyMode(@NonNull WorkSource requestorWs) {
1137         Log.d(TAG, "Switching all primary client mode managers to scan only mode");
1138         for (ConcreteClientModeManager clientModeManager : mClientModeManagers) {
1139             if (clientModeManager.getRole() != ROLE_CLIENT_PRIMARY) {
1140                 continue;
1141             }
1142             clientModeManager.setRole(ROLE_CLIENT_SCAN_ONLY, requestorWs);
1143         }
1144     }
1145 
stopSecondaryClientModeManagers()1146     private void stopSecondaryClientModeManagers() {
1147         stopAllClientModeManagersInRole(ROLE_CLIENT_LOCAL_ONLY);
1148         stopAllClientModeManagersInRole(ROLE_CLIENT_SECONDARY_TRANSIENT);
1149         stopAllClientModeManagersInRole(ROLE_CLIENT_SECONDARY_LONG_LIVED);
1150     }
1151 
1152     /**
1153      * Method to switch all client mode manager mode of operation (from ScanOnly To Connect &
1154      * vice-versa) based on the toggle state.
1155      */
switchAllPrimaryOrScanOnlyClientModeManagers()1156     private boolean switchAllPrimaryOrScanOnlyClientModeManagers() {
1157         Log.d(TAG, "Switching all client mode managers");
1158         for (ConcreteClientModeManager clientModeManager : mClientModeManagers) {
1159             if (clientModeManager.getRole() != ROLE_CLIENT_PRIMARY
1160                     && clientModeManager.getRole() != ROLE_CLIENT_SCAN_ONLY) {
1161                 continue;
1162             }
1163             if (!switchPrimaryOrScanOnlyClientModeManagerRole(clientModeManager)) {
1164                 return false;
1165             }
1166         }
1167         return true;
1168     }
1169 
getRoleForPrimaryOrScanOnlyClientModeManager()1170     private ActiveModeManager.ClientRole getRoleForPrimaryOrScanOnlyClientModeManager() {
1171         if (mSettingsStore.isWifiToggleEnabled()) {
1172             return ROLE_CLIENT_PRIMARY;
1173         } else if (mWifiController.shouldEnableScanOnlyMode()) {
1174             return ROLE_CLIENT_SCAN_ONLY;
1175         } else {
1176             Log.e(TAG, "Something is wrong, no client mode toggles enabled");
1177             return null;
1178         }
1179     }
1180 
1181     /**
1182      * Method to switch a client mode manager mode of operation (from ScanOnly To Connect &
1183      * vice-versa) based on the toggle state.
1184      */
switchPrimaryOrScanOnlyClientModeManagerRole( @onNull ConcreteClientModeManager modeManager)1185     private boolean switchPrimaryOrScanOnlyClientModeManagerRole(
1186             @NonNull ConcreteClientModeManager modeManager) {
1187         ActiveModeManager.ClientRole role = getRoleForPrimaryOrScanOnlyClientModeManager();
1188         final WorkSource lastRequestorWs;
1189         if (role == ROLE_CLIENT_PRIMARY) {
1190             lastRequestorWs = mLastPrimaryClientModeManagerRequestorWs;
1191         } else if (role == ROLE_CLIENT_SCAN_ONLY) {
1192             lastRequestorWs = mLastScanOnlyClientModeManagerRequestorWs;
1193         } else {
1194             return false;
1195         }
1196         modeManager.setRole(role, lastRequestorWs);
1197         return true;
1198     }
1199 
1200     /**
1201      * Method to start a new client mode manager.
1202      */
startAdditionalClientModeManager( ClientConnectivityRole role, @NonNull ExternalClientModeManagerRequestListener externalRequestListener, @NonNull WorkSource requestorWs)1203     private boolean startAdditionalClientModeManager(
1204             ClientConnectivityRole role,
1205             @NonNull ExternalClientModeManagerRequestListener externalRequestListener,
1206             @NonNull WorkSource requestorWs) {
1207         Log.d(TAG, "Starting additional ClientModeManager in role: " + role);
1208         ClientListener listener = new ClientListener(externalRequestListener);
1209         ConcreteClientModeManager manager = mWifiInjector.makeClientModeManager(
1210                 listener, requestorWs, role, mVerboseLoggingEnabled);
1211         mClientModeManagers.add(manager);
1212         return true;
1213     }
1214 
1215     /**
1216      * Method to switch role for an existing non-primary client mode manager.
1217      */
switchRoleForAdditionalClientModeManager( @onNull ConcreteClientModeManager manager, @NonNull ClientConnectivityRole role, @NonNull ExternalClientModeManagerRequestListener externalRequestListener, @NonNull WorkSource requestorWs)1218     private boolean switchRoleForAdditionalClientModeManager(
1219             @NonNull ConcreteClientModeManager manager,
1220             @NonNull ClientConnectivityRole role,
1221             @NonNull ExternalClientModeManagerRequestListener externalRequestListener,
1222             @NonNull WorkSource requestorWs) {
1223         Log.d(TAG, "Switching role for additional ClientModeManager to role: " + role);
1224         ClientListener listener = new ClientListener(externalRequestListener);
1225         manager.setRole(role, requestorWs, listener);
1226         return true;
1227     }
1228 
1229     /**
1230      * Method to stop client mode manager.
1231      */
stopAdditionalClientModeManager(ClientModeManager clientModeManager)1232     private void stopAdditionalClientModeManager(ClientModeManager clientModeManager) {
1233         if (clientModeManager instanceof DefaultClientModeManager
1234                 || clientModeManager.getRole() == ROLE_CLIENT_PRIMARY
1235                 || clientModeManager.getRole() == ROLE_CLIENT_SCAN_ONLY) return;
1236         Log.d(TAG, "Shutting down additional client mode manager: " + clientModeManager);
1237         clientModeManager.stop();
1238     }
1239 
1240     /**
1241      * Method to stop all active modes, for example, when toggling airplane mode.
1242      */
shutdownWifi()1243     private void shutdownWifi() {
1244         Log.d(TAG, "Shutting down all mode managers");
1245         for (ActiveModeManager manager : getActiveModeManagers()) {
1246             manager.stop();
1247         }
1248     }
1249 
1250     /**
1251      * Dump current state for active mode managers.
1252      *
1253      * Must be called from the main Wifi thread.
1254      */
dump(FileDescriptor fd, PrintWriter pw, String[] args)1255     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1256         pw.println("Dump of " + TAG);
1257         pw.println("Current wifi mode: " + getCurrentMode());
1258         pw.println("Wi-Fi is " + getWifiStateName());
1259         pw.println("NumActiveModeManagers: " + getActiveModeManagerCount());
1260         mWifiController.dump(fd, pw, args);
1261         for (ActiveModeManager manager : getActiveModeManagers()) {
1262             manager.dump(fd, pw, args);
1263         }
1264         mGraveyard.dump(fd, pw, args);
1265         boolean isStaStaConcurrencySupported = mWifiNative.isStaStaConcurrencySupported();
1266         pw.println("STA + STA Concurrency Supported: " + isStaStaConcurrencySupported);
1267         if (isStaStaConcurrencySupported) {
1268             pw.println("   MBB use-case enabled: "
1269                     + mContext.getResources().getBoolean(
1270                             R.bool.config_wifiMultiStaNetworkSwitchingMakeBeforeBreakEnabled));
1271             pw.println("   Local only use-case enabled: "
1272                     + mContext.getResources().getBoolean(
1273                             R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled));
1274             pw.println("   Restricted use-case enabled: "
1275                     + mContext.getResources().getBoolean(
1276                             R.bool.config_wifiMultiStaRestrictedConcurrencyEnabled));
1277             pw.println("   Multi internet use-case enabled: "
1278                     + mContext.getResources().getBoolean(
1279                             R.bool.config_wifiMultiStaMultiInternetConcurrencyEnabled));
1280         }
1281         pw.println("STA + AP Concurrency Supported: " + isStaApConcurrencySupported());
1282         mWifiInjector.getHalDeviceManager().dump(fd, pw, args);
1283     }
1284 
1285     @VisibleForTesting
getCurrentMode()1286     String getCurrentMode() {
1287         IState state = mWifiController.getCurrentState();
1288         return state == null ? STATE_MACHINE_EXITED_STATE_NAME : state.getName();
1289     }
1290 
1291     @VisibleForTesting
getActiveModeManagers()1292     Collection<ActiveModeManager> getActiveModeManagers() {
1293         ArrayList<ActiveModeManager> activeModeManagers = new ArrayList<>();
1294         activeModeManagers.addAll(mClientModeManagers);
1295         activeModeManagers.addAll(mSoftApManagers);
1296         return activeModeManagers;
1297     }
1298 
getActiveModeManagerCount()1299     private int getActiveModeManagerCount() {
1300         return mSoftApManagers.size() + mClientModeManagers.size();
1301     }
1302 
1303     @VisibleForTesting
isInEmergencyMode()1304     boolean isInEmergencyMode() {
1305         IState state = mWifiController.getCurrentState();
1306         return ((WifiController.BaseState) state).isInEmergencyMode();
1307     }
1308 
updateBatteryStats()1309     private void updateBatteryStats() {
1310         updateBatteryStatsWifiState(hasAnyModeManager());
1311         if (areAllClientModeManagersInScanOnlyRole()) {
1312             updateBatteryStatsScanModeActive();
1313         }
1314     }
1315 
1316     private class SoftApListener implements ActiveModeManager.Listener<SoftApManager> {
1317         @Override
onStarted(SoftApManager softApManager)1318         public void onStarted(SoftApManager softApManager) {
1319             updateBatteryStats();
1320             invokeOnAddedCallbacks(softApManager);
1321         }
1322 
1323         @Override
onRoleChanged(SoftApManager softApManager)1324         public void onRoleChanged(SoftApManager softApManager) {
1325             Log.w(TAG, "Role switched received on SoftApManager unexpectedly");
1326         }
1327 
1328         @Override
onStopped(SoftApManager softApManager)1329         public void onStopped(SoftApManager softApManager) {
1330             mSoftApManagers.remove(softApManager);
1331             mGraveyard.inter(softApManager);
1332             updateBatteryStats();
1333             mWifiController.sendMessage(WifiController.CMD_AP_STOPPED);
1334             invokeOnRemovedCallbacks(softApManager);
1335         }
1336 
1337         @Override
onStartFailure(SoftApManager softApManager)1338         public void onStartFailure(SoftApManager softApManager) {
1339             mSoftApManagers.remove(softApManager);
1340             mGraveyard.inter(softApManager);
1341             updateBatteryStats();
1342             mWifiController.sendMessage(WifiController.CMD_AP_START_FAILURE);
1343             // onStartFailure can be called when switching between roles. So, remove
1344             // update listeners.
1345             Log.e(TAG, "SoftApManager start failed!" + softApManager);
1346             invokeOnRemovedCallbacks(softApManager);
1347         }
1348     }
1349 
1350     private class ClientListener implements ActiveModeManager.Listener<ConcreteClientModeManager> {
1351         @Nullable
1352         private ExternalClientModeManagerRequestListener mExternalRequestListener; // one shot
1353 
ClientListener()1354         ClientListener() {
1355             this(null);
1356         }
1357 
ClientListener( @ullable ExternalClientModeManagerRequestListener externalRequestListener)1358         ClientListener(
1359                 @Nullable ExternalClientModeManagerRequestListener externalRequestListener) {
1360             mExternalRequestListener = externalRequestListener;
1361         }
1362 
1363         @WifiNative.MultiStaUseCase
getMultiStatUseCase()1364         private int getMultiStatUseCase() {
1365             // Note: The use-case setting finds the first non-primary client mode manager to set
1366             // the use-case to HAL. This does not extend to 3 STA concurrency when there are
1367             // 2 secondary STA client mode managers.
1368             for (ClientModeManager cmm : getClientModeManagers()) {
1369                 ClientRole clientRole = cmm.getRole();
1370                 if (clientRole == ROLE_CLIENT_LOCAL_ONLY
1371                         || clientRole == ROLE_CLIENT_SECONDARY_LONG_LIVED) {
1372                     return WifiNative.DUAL_STA_NON_TRANSIENT_UNBIASED;
1373                 } else if (clientRole == ROLE_CLIENT_SECONDARY_TRANSIENT) {
1374                     return WifiNative.DUAL_STA_TRANSIENT_PREFER_PRIMARY;
1375                 }
1376             }
1377             // if single STA, a safe default is PREFER_PRIMARY
1378             return WifiNative.DUAL_STA_TRANSIENT_PREFER_PRIMARY;
1379         }
1380 
1381         /**
1382          * Hardware needs to be configured for STA + STA before sending the callbacks to clients
1383          * letting them know that CM is ready for use.
1384          */
configureHwForMultiStaIfNecessary()1385         private void configureHwForMultiStaIfNecessary() {
1386             mWifiNative.setMultiStaUseCase(getMultiStatUseCase());
1387             String primaryIfaceName = getPrimaryClientModeManager().getInterfaceName();
1388             // if no primary exists (occurs briefly during Make Before Break), don't update the
1389             // primary and keep the previous primary. Only update WifiNative when the new primary is
1390             // activated.
1391             if (primaryIfaceName != null) {
1392                 mWifiNative.setMultiStaPrimaryConnection(primaryIfaceName);
1393             }
1394         }
1395 
onStartedOrRoleChanged(ConcreteClientModeManager clientModeManager)1396         private void onStartedOrRoleChanged(ConcreteClientModeManager clientModeManager) {
1397             updateClientScanMode();
1398             updateBatteryStats();
1399             configureHwForMultiStaIfNecessary();
1400             if (mExternalRequestListener != null) {
1401                 mExternalRequestListener.onAnswer(clientModeManager);
1402                 mExternalRequestListener = null; // reset after one shot.
1403             }
1404 
1405             // Report to SarManager
1406             reportWifiStateToSarManager();
1407         }
1408 
reportWifiStateToSarManager()1409         private void reportWifiStateToSarManager() {
1410             if (areAllClientModeManagersInScanOnlyRole()) {
1411                 // Inform sar manager that scan only is being enabled
1412                 mWifiInjector.getSarManager().setScanOnlyWifiState(WifiManager.WIFI_STATE_ENABLED);
1413             } else {
1414                 // Inform sar manager that scan only is being disabled
1415                 mWifiInjector.getSarManager().setScanOnlyWifiState(WifiManager.WIFI_STATE_DISABLED);
1416             }
1417             if (hasAnyClientModeManagerInConnectivityRole()) {
1418                 // Inform sar manager that wifi is Enabled
1419                 mWifiInjector.getSarManager().setClientWifiState(WifiManager.WIFI_STATE_ENABLED);
1420             } else {
1421                 // Inform sar manager that wifi is being disabled
1422                 mWifiInjector.getSarManager().setClientWifiState(WifiManager.WIFI_STATE_DISABLED);
1423             }
1424         }
1425 
onPrimaryChangedDueToStartedOrRoleChanged( ConcreteClientModeManager clientModeManager)1426         private void onPrimaryChangedDueToStartedOrRoleChanged(
1427                 ConcreteClientModeManager clientModeManager) {
1428             if (clientModeManager.getRole() != ROLE_CLIENT_PRIMARY
1429                     && clientModeManager == mLastPrimaryClientModeManager) {
1430                 // CMM was primary, but is no longer primary
1431                 invokeOnPrimaryClientModeManagerChangedCallbacks(clientModeManager, null);
1432                 mLastPrimaryClientModeManager = null;
1433             } else if (clientModeManager.getRole() == ROLE_CLIENT_PRIMARY
1434                     && clientModeManager != mLastPrimaryClientModeManager) {
1435                 // CMM is primary, but wasn't primary before
1436                 invokeOnPrimaryClientModeManagerChangedCallbacks(
1437                         mLastPrimaryClientModeManager, clientModeManager);
1438                 mLastPrimaryClientModeManager = clientModeManager;
1439             }
1440         }
1441 
1442         @Override
onStarted(@onNull ConcreteClientModeManager clientModeManager)1443         public void onStarted(@NonNull ConcreteClientModeManager clientModeManager) {
1444             onStartedOrRoleChanged(clientModeManager);
1445             invokeOnAddedCallbacks(clientModeManager);
1446             // invoke "added" callbacks before primary changed
1447             onPrimaryChangedDueToStartedOrRoleChanged(clientModeManager);
1448         }
1449 
1450         @Override
onRoleChanged(@onNull ConcreteClientModeManager clientModeManager)1451         public void onRoleChanged(@NonNull ConcreteClientModeManager clientModeManager) {
1452             onStartedOrRoleChanged(clientModeManager);
1453             invokeOnRoleChangedCallbacks(clientModeManager);
1454             onPrimaryChangedDueToStartedOrRoleChanged(clientModeManager);
1455         }
1456 
onStoppedOrStartFailure(ConcreteClientModeManager clientModeManager)1457         private void onStoppedOrStartFailure(ConcreteClientModeManager clientModeManager) {
1458             mClientModeManagers.remove(clientModeManager);
1459             mGraveyard.inter(clientModeManager);
1460             updateClientScanMode();
1461             updateBatteryStats();
1462             if (clientModeManager == mLastPrimaryClientModeManager) {
1463                 // CMM was primary, but was stopped
1464                 invokeOnPrimaryClientModeManagerChangedCallbacks(
1465                         mLastPrimaryClientModeManager, null);
1466                 mLastPrimaryClientModeManager = null;
1467             }
1468             // invoke "removed" callbacks after primary changed
1469             invokeOnRemovedCallbacks(clientModeManager);
1470 
1471             // Report to SarManager
1472             reportWifiStateToSarManager();
1473         }
1474 
1475         @Override
onStopped(@onNull ConcreteClientModeManager clientModeManager)1476         public void onStopped(@NonNull ConcreteClientModeManager clientModeManager) {
1477             onStoppedOrStartFailure(clientModeManager);
1478             mWifiController.sendMessage(WifiController.CMD_STA_STOPPED);
1479         }
1480 
1481         @Override
onStartFailure(@onNull ConcreteClientModeManager clientModeManager)1482         public void onStartFailure(@NonNull ConcreteClientModeManager clientModeManager) {
1483             Log.e(TAG, "ClientModeManager start failed!" + clientModeManager);
1484             // onStartFailure can be called when switching between roles. So, remove
1485             // update listeners.
1486             onStoppedOrStartFailure(clientModeManager);
1487             mWifiController.sendMessage(WifiController.CMD_STA_START_FAILURE);
1488         }
1489     }
1490 
1491     // Update the scan state based on all active mode managers.
updateClientScanMode()1492     private void updateClientScanMode() {
1493         boolean scanEnabled = hasAnyClientModeManager();
1494         boolean scanningForHiddenNetworksEnabled;
1495 
1496         if (mContext.getResources().getBoolean(R.bool.config_wifiScanHiddenNetworksScanOnlyMode)) {
1497             scanningForHiddenNetworksEnabled = hasAnyClientModeManager();
1498         } else {
1499             scanningForHiddenNetworksEnabled = hasAnyClientModeManagerInConnectivityRole();
1500         }
1501         mScanRequestProxy.enableScanning(scanEnabled, scanningForHiddenNetworksEnabled);
1502     }
1503 
1504     /**
1505      *  Helper method to report wifi state as on/off (doesn't matter which mode).
1506      *
1507      *  @param enabled boolean indicating that some mode has been turned on or off
1508      */
updateBatteryStatsWifiState(boolean enabled)1509     private void updateBatteryStatsWifiState(boolean enabled) {
1510         if (enabled) {
1511             if (getActiveModeManagerCount() == 1) {
1512                 // only report wifi on if we haven't already
1513                 mBatteryStatsManager.reportWifiOn();
1514             }
1515         } else {
1516             if (getActiveModeManagerCount() == 0) {
1517                 // only report if we don't have any active modes
1518                 mBatteryStatsManager.reportWifiOff();
1519             }
1520         }
1521     }
1522 
updateBatteryStatsScanModeActive()1523     private void updateBatteryStatsScanModeActive() {
1524         mBatteryStatsManager.reportWifiState(BatteryStatsManager.WIFI_STATE_OFF_SCANNING, null);
1525     }
1526 
1527     /**
1528      * Called to pull metrics from ActiveModeWarden to WifiMetrics when a dump is triggered, as
1529      * opposed to the more common push metrics which are reported to WifiMetrics as soon as they
1530      * occur.
1531      */
updateMetrics()1532     public void updateMetrics() {
1533         mWifiMetrics.setIsMakeBeforeBreakSupported(isStaStaConcurrencySupportedForMbb());
1534     }
1535 
1536     /**
1537      * During Wifi off -> on transition, there is a race condition between country code update,
1538      * single scan triggered by App based ACTION_WIFI_SCAN_AVAILABILITY_CHANGED. The single scan
1539      * might fail if country code is updated while the scan is ongoing.
1540      * To mitigate that issue, send ACTION_WIFI_SCAN_AVAILABILITY_CHANGED again when the country
1541      * code update is completed.
1542      *
1543      * @param newCountryCode the new country code, null when there is no active mode enabled.
1544      */
updateClientScanModeAfterCountryCodeUpdate(@ullable String newCountryCode)1545     public void updateClientScanModeAfterCountryCodeUpdate(@Nullable String newCountryCode) {
1546         // Handle country code changed only during Wifi off -> on transition.
1547         if (newCountryCode != null) {
1548             updateClientScanMode();
1549         }
1550     }
1551 
1552     /**
1553      * WifiController is the class used to manage wifi state for various operating
1554      * modes (normal, airplane, wifi hotspot, etc.).
1555      */
1556     private class WifiController extends StateMachine {
1557         private static final String TAG = "WifiController";
1558 
1559         // Maximum limit to use for timeout delay if the value from overlay setting is too large.
1560         private static final int MAX_RECOVERY_TIMEOUT_DELAY_MS = 4000;
1561 
1562         private static final int BASE = Protocol.BASE_WIFI_CONTROLLER;
1563 
1564         static final int CMD_EMERGENCY_MODE_CHANGED                 = BASE + 1;
1565         static final int CMD_EMERGENCY_SCAN_STATE_CHANGED           = BASE + 2;
1566         static final int CMD_SCAN_ALWAYS_MODE_CHANGED               = BASE + 7;
1567         static final int CMD_WIFI_TOGGLED                           = BASE + 8;
1568         static final int CMD_AIRPLANE_TOGGLED                       = BASE + 9;
1569         static final int CMD_SET_AP                                 = BASE + 10;
1570         static final int CMD_EMERGENCY_CALL_STATE_CHANGED           = BASE + 14;
1571         static final int CMD_AP_STOPPED                             = BASE + 15;
1572         static final int CMD_STA_START_FAILURE                      = BASE + 16;
1573         // Command used to trigger a wifi stack restart when in active mode
1574         static final int CMD_RECOVERY_RESTART_WIFI                  = BASE + 17;
1575         // Internal command used to complete wifi stack restart
1576         private static final int CMD_RECOVERY_RESTART_WIFI_CONTINUE = BASE + 18;
1577         // Command to disable wifi when SelfRecovery is throttled or otherwise not doing full
1578         // recovery
1579         static final int CMD_RECOVERY_DISABLE_WIFI                   = BASE + 19;
1580         static final int CMD_STA_STOPPED                             = BASE + 20;
1581         static final int CMD_DEFERRED_RECOVERY_RESTART_WIFI          = BASE + 22;
1582         static final int CMD_AP_START_FAILURE                        = BASE + 23;
1583         static final int CMD_UPDATE_AP_CAPABILITY                    = BASE + 24;
1584         static final int CMD_UPDATE_AP_CONFIG                        = BASE + 25;
1585         static final int CMD_REQUEST_ADDITIONAL_CLIENT_MODE_MANAGER  = BASE + 26;
1586         static final int CMD_REMOVE_ADDITIONAL_CLIENT_MODE_MANAGER   = BASE + 27;
1587 
1588         private final EnabledState mEnabledState = new EnabledState();
1589         private final DisabledState mDisabledState = new DisabledState();
1590 
1591         private boolean mIsInEmergencyCall = false;
1592         private boolean mIsInEmergencyCallbackMode = false;
1593         private boolean mIsEmergencyScanInProgress = false;
1594 
WifiController()1595         WifiController() {
1596             super(TAG, mLooper);
1597 
1598             DefaultState defaultState = new DefaultState();
1599             addState(defaultState); {
1600                 addState(mDisabledState, defaultState);
1601                 addState(mEnabledState, defaultState);
1602             }
1603 
1604             setLogRecSize(100);
1605             setLogOnlyTransitions(false);
1606 
1607         }
1608 
1609         @Override
getWhatToString(int what)1610         protected String getWhatToString(int what) {
1611             switch (what) {
1612                 case CMD_AIRPLANE_TOGGLED:
1613                     return "CMD_AIRPLANE_TOGGLED";
1614                 case CMD_AP_START_FAILURE:
1615                     return "CMD_AP_START_FAILURE";
1616                 case CMD_AP_STOPPED:
1617                     return "CMD_AP_STOPPED";
1618                 case CMD_DEFERRED_RECOVERY_RESTART_WIFI:
1619                     return "CMD_DEFERRED_RECOVERY_RESTART_WIFI";
1620                 case CMD_EMERGENCY_CALL_STATE_CHANGED:
1621                     return "CMD_EMERGENCY_CALL_STATE_CHANGED";
1622                 case CMD_EMERGENCY_MODE_CHANGED:
1623                     return "CMD_EMERGENCY_MODE_CHANGED";
1624                 case CMD_RECOVERY_DISABLE_WIFI:
1625                     return "CMD_RECOVERY_DISABLE_WIFI";
1626                 case CMD_RECOVERY_RESTART_WIFI:
1627                     return "CMD_RECOVERY_RESTART_WIFI";
1628                 case CMD_RECOVERY_RESTART_WIFI_CONTINUE:
1629                     return "CMD_RECOVERY_RESTART_WIFI_CONTINUE";
1630                 case CMD_REMOVE_ADDITIONAL_CLIENT_MODE_MANAGER:
1631                     return "CMD_REMOVE_ADDITIONAL_CLIENT_MODE_MANAGER";
1632                 case CMD_REQUEST_ADDITIONAL_CLIENT_MODE_MANAGER:
1633                     return "CMD_REQUEST_ADDITIONAL_CLIENT_MODE_MANAGER";
1634                 case CMD_EMERGENCY_SCAN_STATE_CHANGED:
1635                     return "CMD_EMERGENCY_SCAN_STATE_CHANGED";
1636                 case CMD_SCAN_ALWAYS_MODE_CHANGED:
1637                     return "CMD_SCAN_ALWAYS_MODE_CHANGED";
1638                 case CMD_SET_AP:
1639                     return "CMD_SET_AP";
1640                 case CMD_STA_START_FAILURE:
1641                     return "CMD_STA_START_FAILURE";
1642                 case CMD_STA_STOPPED:
1643                     return "CMD_STA_STOPPED";
1644                 case CMD_UPDATE_AP_CAPABILITY:
1645                     return "CMD_UPDATE_AP_CAPABILITY";
1646                 case CMD_UPDATE_AP_CONFIG:
1647                     return "CMD_UPDATE_AP_CONFIG";
1648                 case CMD_WIFI_TOGGLED:
1649                     return "CMD_WIFI_TOGGLED";
1650                 default:
1651                     return "what:" + what;
1652             }
1653         }
1654 
1655         @Override
start()1656         public void start() {
1657             boolean isAirplaneModeOn = mSettingsStore.isAirplaneModeOn();
1658             boolean isWifiEnabled = mSettingsStore.isWifiToggleEnabled();
1659             boolean isScanningAlwaysAvailable = mSettingsStore.isScanAlwaysAvailable();
1660             boolean isLocationModeActive = mWifiPermissionsUtil.isLocationModeEnabled();
1661 
1662             log("isAirplaneModeOn = " + isAirplaneModeOn
1663                     + ", isWifiEnabled = " + isWifiEnabled
1664                     + ", isScanningAvailable = " + isScanningAlwaysAvailable
1665                     + ", isLocationModeActive = " + isLocationModeActive);
1666 
1667             // Initialize these values at bootup to defaults, will be overridden by API calls
1668             // for further toggles.
1669             mLastPrimaryClientModeManagerRequestorWs = mFacade.getSettingsWorkSource(mContext);
1670             mLastScanOnlyClientModeManagerRequestorWs = INTERNAL_REQUESTOR_WS;
1671             ActiveModeManager.ClientRole role = getRoleForPrimaryOrScanOnlyClientModeManager();
1672             if (role == ROLE_CLIENT_PRIMARY) {
1673                 startPrimaryClientModeManager(mLastPrimaryClientModeManagerRequestorWs);
1674                 setInitialState(mEnabledState);
1675             } else if (role == ROLE_CLIENT_SCAN_ONLY) {
1676                 startScanOnlyClientModeManager(mLastScanOnlyClientModeManagerRequestorWs);
1677                 setInitialState(mEnabledState);
1678             } else {
1679                 setInitialState(mDisabledState);
1680             }
1681             mWifiMetrics.noteWifiEnabledDuringBoot(mSettingsStore.isWifiToggleEnabled());
1682 
1683             // Initialize the lower layers before we start.
1684             mWifiNative.initialize();
1685             super.start();
1686         }
1687 
readWifiRecoveryDelay()1688         private int readWifiRecoveryDelay() {
1689             int recoveryDelayMillis = mContext.getResources().getInteger(
1690                     R.integer.config_wifi_framework_recovery_timeout_delay);
1691             if (recoveryDelayMillis > MAX_RECOVERY_TIMEOUT_DELAY_MS) {
1692                 recoveryDelayMillis = MAX_RECOVERY_TIMEOUT_DELAY_MS;
1693                 Log.w(TAG, "Overriding timeout delay with maximum limit value");
1694             }
1695             return recoveryDelayMillis;
1696         }
1697 
1698         abstract class BaseState extends State {
1699             @VisibleForTesting
isInEmergencyMode()1700             boolean isInEmergencyMode() {
1701                 return mIsInEmergencyCall || mIsInEmergencyCallbackMode;
1702             }
1703 
1704             /** Device is in emergency mode & carrier config requires wifi off in emergency mode */
isInEmergencyModeWhichRequiresWifiDisable()1705             private boolean isInEmergencyModeWhichRequiresWifiDisable() {
1706                 return isInEmergencyMode() && mFacade.getConfigWiFiDisableInECBM(mContext);
1707             }
1708 
updateEmergencyMode(Message msg)1709             private void updateEmergencyMode(Message msg) {
1710                 if (msg.what == CMD_EMERGENCY_CALL_STATE_CHANGED) {
1711                     mIsInEmergencyCall = msg.arg1 == 1;
1712                 } else if (msg.what == CMD_EMERGENCY_MODE_CHANGED) {
1713                     mIsInEmergencyCallbackMode = msg.arg1 == 1;
1714                 }
1715             }
1716 
enterEmergencyMode()1717             private void enterEmergencyMode() {
1718                 stopSoftApModeManagers(WifiManager.IFACE_IP_MODE_UNSPECIFIED);
1719                 boolean configWiFiDisableInECBM = mFacade.getConfigWiFiDisableInECBM(mContext);
1720                 log("Entering emergency callback mode, "
1721                         + "CarrierConfigManager.KEY_CONFIG_WIFI_DISABLE_IN_ECBM: "
1722                         + configWiFiDisableInECBM);
1723                 if (!mIsEmergencyScanInProgress) {
1724                     if (configWiFiDisableInECBM) {
1725                         shutdownWifi();
1726                     }
1727                 } else {
1728                     if (configWiFiDisableInECBM) {
1729                         switchAllPrimaryClientModeManagersToScanOnlyMode(
1730                                 mFacade.getSettingsWorkSource(mContext));
1731                     }
1732                 }
1733             }
1734 
exitEmergencyMode()1735             private void exitEmergencyMode() {
1736                 log("Exiting emergency callback mode");
1737                 // may be in DisabledState or EnabledState (depending on whether Wifi was shut down
1738                 // in enterEmergencyMode() or not based on getConfigWiFiDisableInECBM).
1739                 // Let CMD_WIFI_TOGGLED handling decide what the next state should be, or if we're
1740                 // already in the correct state.
1741 
1742                 // Assumes user toggled it on from settings before.
1743                 wifiToggled(mFacade.getSettingsWorkSource(mContext));
1744             }
1745 
processMessageInEmergencyMode(Message msg)1746             private boolean processMessageInEmergencyMode(Message msg) {
1747                 // In emergency mode: Some messages need special handling in this mode,
1748                 // all others are dropped.
1749                 switch (msg.what) {
1750                     case CMD_STA_STOPPED:
1751                     case CMD_AP_STOPPED:
1752                         log("Processing message in Emergency Callback Mode: " + msg);
1753                         if (!hasAnyModeManager()) {
1754                             log("No active mode managers, return to DisabledState.");
1755                             transitionTo(mDisabledState);
1756                         }
1757                         break;
1758                     case CMD_SET_AP:
1759                         // arg1 == 1 => enable AP
1760                         if (msg.arg1 == 1) {
1761                             log("AP cannot be started in Emergency Callback Mode: " + msg);
1762                             // SoftAP was disabled upon entering emergency mode. It also cannot
1763                             // be re-enabled during emergency mode. Drop the message and invoke
1764                             // the failure callback.
1765                             Pair<SoftApModeConfiguration, WorkSource> softApConfigAndWs =
1766                                     (Pair<SoftApModeConfiguration, WorkSource>) msg.obj;
1767                             SoftApModeConfiguration softApConfig = softApConfigAndWs.first;
1768                             WifiServiceImpl.SoftApCallbackInternal callback =
1769                                     softApConfig.getTargetMode() == IFACE_IP_MODE_LOCAL_ONLY
1770                                             ? mLohsCallback : mSoftApCallback;
1771                             // need to notify SoftApCallback that start/stop AP failed
1772                             callback.onStateChanged(WifiManager.WIFI_AP_STATE_FAILED,
1773                                     WifiManager.SAP_START_FAILURE_GENERAL);
1774                         }
1775                         break;
1776                     default:
1777                         log("Dropping message in emergency callback mode: " + msg);
1778                         break;
1779 
1780                 }
1781                 return HANDLED;
1782             }
1783 
handleEmergencyModeStateChange(Message msg)1784             private void handleEmergencyModeStateChange(Message msg) {
1785                 boolean wasInEmergencyMode = isInEmergencyMode();
1786                 updateEmergencyMode(msg);
1787                 boolean isInEmergencyMode = isInEmergencyMode();
1788                 if (!wasInEmergencyMode && isInEmergencyMode) {
1789                     enterEmergencyMode();
1790                 } else if (wasInEmergencyMode && !isInEmergencyMode) {
1791                     exitEmergencyMode();
1792                 }
1793             }
1794 
handleEmergencyScanStateChange(Message msg)1795             private void handleEmergencyScanStateChange(Message msg) {
1796                 final boolean scanInProgress = msg.arg1 == 1;
1797                 final WorkSource requestorWs = (WorkSource) msg.obj;
1798                 log("Processing scan state change: " + scanInProgress);
1799                 mIsEmergencyScanInProgress = scanInProgress;
1800                 if (isInEmergencyModeWhichRequiresWifiDisable())  {
1801                     // If wifi was disabled because of emergency mode
1802                     // (getConfigWiFiDisableInECBM == true), don't use the
1803                     // generic method to handle toggle change since that may put wifi in
1804                     // connectivity mode (since wifi toggle may actually be on underneath)
1805                     if (getCurrentState() == mDisabledState && scanInProgress) {
1806                         // go to scan only mode.
1807                         startScanOnlyClientModeManager(requestorWs);
1808                         transitionTo(mEnabledState);
1809                     } else if (getCurrentState() == mEnabledState && !scanInProgress) {
1810                         // shut down to go back to previous state.
1811                         stopAllClientModeManagers();
1812                     }
1813                 } else {
1814                     if (getCurrentState() == mDisabledState) {
1815                         handleStaToggleChangeInDisabledState(requestorWs);
1816                     } else if (getCurrentState() == mEnabledState) {
1817                         handleStaToggleChangeInEnabledState(requestorWs);
1818                     }
1819                 }
1820             }
1821 
1822             @Override
processMessage(Message msg)1823             public final boolean processMessage(Message msg) {
1824                 // potentially enter emergency mode
1825                 if (msg.what == CMD_EMERGENCY_CALL_STATE_CHANGED
1826                         || msg.what == CMD_EMERGENCY_MODE_CHANGED) {
1827                     handleEmergencyModeStateChange(msg);
1828                     return HANDLED;
1829                 } else if (msg.what == CMD_EMERGENCY_SCAN_STATE_CHANGED) {
1830                     // emergency scans need to be allowed even in emergency mode.
1831                     handleEmergencyScanStateChange(msg);
1832                     return HANDLED;
1833                 } else if (isInEmergencyMode()) {
1834                     return processMessageInEmergencyMode(msg);
1835                 } else {
1836                     // not in emergency mode, process messages normally
1837                     return processMessageFiltered(msg);
1838                 }
1839             }
1840 
processMessageFiltered(Message msg)1841             protected abstract boolean processMessageFiltered(Message msg);
1842         }
1843 
1844         class DefaultState extends State {
1845             @Override
processMessage(Message msg)1846             public boolean processMessage(Message msg) {
1847                 switch (msg.what) {
1848                     case CMD_SCAN_ALWAYS_MODE_CHANGED:
1849                     case CMD_EMERGENCY_SCAN_STATE_CHANGED:
1850                     case CMD_WIFI_TOGGLED:
1851                     case CMD_STA_STOPPED:
1852                     case CMD_STA_START_FAILURE:
1853                     case CMD_AP_STOPPED:
1854                     case CMD_AP_START_FAILURE:
1855                     case CMD_RECOVERY_RESTART_WIFI:
1856                     case CMD_RECOVERY_RESTART_WIFI_CONTINUE:
1857                     case CMD_DEFERRED_RECOVERY_RESTART_WIFI:
1858                     case CMD_REMOVE_ADDITIONAL_CLIENT_MODE_MANAGER:
1859                         break;
1860                     case CMD_REQUEST_ADDITIONAL_CLIENT_MODE_MANAGER:
1861                         AdditionalClientModeManagerRequestInfo requestInfo =
1862                                 (AdditionalClientModeManagerRequestInfo) msg.obj;
1863                         requestInfo.listener.onAnswer(null);
1864                         break;
1865                     case CMD_RECOVERY_DISABLE_WIFI:
1866                         log("Recovery has been throttled, disable wifi");
1867                         shutdownWifi();
1868                         // onStopped will move the state machine to "DisabledState".
1869                         break;
1870                     case CMD_AIRPLANE_TOGGLED:
1871                         if (mSettingsStore.isAirplaneModeOn()) {
1872                             log("Airplane mode toggled, shutdown all modes");
1873                             shutdownWifi();
1874                             // onStopped will move the state machine to "DisabledState".
1875                         } else {
1876                             log("Airplane mode disabled, determine next state");
1877                             if (shouldEnableSta()) {
1878                                 startPrimaryOrScanOnlyClientModeManager(
1879                                         // Assumes user toggled it on from settings before.
1880                                         mFacade.getSettingsWorkSource(mContext));
1881                                 transitionTo(mEnabledState);
1882                             }
1883                             // wifi should remain disabled, do not need to transition
1884                         }
1885                         break;
1886                     case CMD_UPDATE_AP_CAPABILITY:
1887                         updateCapabilityToSoftApModeManager((SoftApCapability) msg.obj, msg.arg1);
1888                         break;
1889                     case CMD_UPDATE_AP_CONFIG:
1890                         updateConfigurationToSoftApModeManager((SoftApConfiguration) msg.obj);
1891                         break;
1892                     default:
1893                         throw new RuntimeException("WifiController.handleMessage " + msg.what);
1894                 }
1895                 return HANDLED;
1896             }
1897         }
1898 
shouldEnableScanOnlyMode()1899         private boolean shouldEnableScanOnlyMode() {
1900             return (mWifiPermissionsUtil.isLocationModeEnabled()
1901                     && mSettingsStore.isScanAlwaysAvailable())
1902                     || mIsEmergencyScanInProgress;
1903         }
1904 
shouldEnableSta()1905         private boolean shouldEnableSta() {
1906             return mSettingsStore.isWifiToggleEnabled() || shouldEnableScanOnlyMode();
1907         }
1908 
handleStaToggleChangeInDisabledState(WorkSource requestorWs)1909         private void handleStaToggleChangeInDisabledState(WorkSource requestorWs) {
1910             if (shouldEnableSta()) {
1911                 startPrimaryOrScanOnlyClientModeManager(requestorWs);
1912                 transitionTo(mEnabledState);
1913             }
1914         }
1915 
handleStaToggleChangeInEnabledState(WorkSource requestorWs)1916         private void handleStaToggleChangeInEnabledState(WorkSource requestorWs) {
1917             if (shouldEnableSta()) {
1918                 if (hasPrimaryOrScanOnlyModeManager()) {
1919                     if (!mSettingsStore.isWifiToggleEnabled()) {
1920                         // Wifi is turned off, so we should stop all the secondary CMMs which are
1921                         // currently all for connectivity purpose. It's important to stops the
1922                         // secondary CMMs before switch state of the primary CMM so features using
1923                         // those secondary CMMs knows to abort properly, and won't react in strange
1924                         // ways to the primary switching to scan only mode later.
1925                         stopSecondaryClientModeManagers();
1926                     }
1927                     switchAllPrimaryOrScanOnlyClientModeManagers();
1928                 } else {
1929                     startPrimaryOrScanOnlyClientModeManager(requestorWs);
1930                 }
1931             } else {
1932                 stopAllClientModeManagers();
1933             }
1934         }
1935 
1936         class DisabledState extends BaseState {
1937             @Override
enter()1938             public void enter() {
1939                 log("DisabledState.enter()");
1940                 super.enter();
1941                 if (hasAnyModeManager()) {
1942                     Log.e(TAG, "Entered DisabledState, but has active mode managers");
1943                 }
1944             }
1945 
1946             @Override
exit()1947             public void exit() {
1948                 log("DisabledState.exit()");
1949                 super.exit();
1950             }
1951 
1952             @Override
processMessageFiltered(Message msg)1953             public boolean processMessageFiltered(Message msg) {
1954                 switch (msg.what) {
1955                     case CMD_WIFI_TOGGLED:
1956                     case CMD_SCAN_ALWAYS_MODE_CHANGED:
1957                         handleStaToggleChangeInDisabledState((WorkSource) msg.obj);
1958                         break;
1959                     case CMD_SET_AP:
1960                         // note: CMD_SET_AP is handled/dropped in ECM mode - will not start here
1961                         if (msg.arg1 == 1) {
1962                             Pair<SoftApModeConfiguration, WorkSource> softApConfigAndWs =
1963                                     (Pair) msg.obj;
1964                             startSoftApModeManager(
1965                                     softApConfigAndWs.first, softApConfigAndWs.second);
1966                             transitionTo(mEnabledState);
1967                         }
1968                         break;
1969                     case CMD_RECOVERY_RESTART_WIFI:
1970                         log("Recovery triggered, already in disabled state");
1971                         sendMessageDelayed(CMD_RECOVERY_RESTART_WIFI_CONTINUE,
1972                                 Collections.emptyList(), readWifiRecoveryDelay());
1973                         break;
1974                     case CMD_DEFERRED_RECOVERY_RESTART_WIFI:
1975                         // wait mRecoveryDelayMillis for letting driver clean reset.
1976                         sendMessageDelayed(CMD_RECOVERY_RESTART_WIFI_CONTINUE,
1977                                 msg.obj, readWifiRecoveryDelay());
1978                         break;
1979                     case CMD_RECOVERY_RESTART_WIFI_CONTINUE:
1980                         log("Recovery in progress, start wifi");
1981                         List<ActiveModeManager> modeManagersBeforeRecovery = (List) msg.obj;
1982                         // No user controlled mode managers before recovery, so check if wifi
1983                         // was toggled on.
1984                         if (modeManagersBeforeRecovery.isEmpty()) {
1985                             if (shouldEnableSta()) {
1986                                 startPrimaryOrScanOnlyClientModeManager(
1987                                         // Assumes user toggled it on from settings before.
1988                                         mFacade.getSettingsWorkSource(mContext));
1989                                 transitionTo(mEnabledState);
1990                             }
1991                             break;
1992                         }
1993                         for (ActiveModeManager activeModeManager : modeManagersBeforeRecovery) {
1994                             if (activeModeManager instanceof ConcreteClientModeManager) {
1995                                 startPrimaryOrScanOnlyClientModeManager(
1996                                         activeModeManager.getRequestorWs());
1997                             } else if (activeModeManager instanceof SoftApManager) {
1998                                 SoftApManager softApManager = (SoftApManager) activeModeManager;
1999                                 startSoftApModeManager(
2000                                         softApManager.getSoftApModeConfiguration(),
2001                                         softApManager.getRequestorWs());
2002                             }
2003                         }
2004                         transitionTo(mEnabledState);
2005                         int numCallbacks = mRestartCallbacks.beginBroadcast();
2006                         for (int i = 0; i < numCallbacks; i++) {
2007                             try {
2008                                 mRestartCallbacks.getBroadcastItem(i).onSubsystemRestarted();
2009                             } catch (RemoteException e) {
2010                                 Log.e(TAG, "Failure calling onSubsystemRestarted" + e);
2011                             }
2012                         }
2013                         mRestartCallbacks.finishBroadcast();
2014                         mWifiInjector.getSelfRecovery().onRecoveryCompleted();
2015                         break;
2016                     default:
2017                         return NOT_HANDLED;
2018                 }
2019                 return HANDLED;
2020             }
2021         }
2022 
2023         class EnabledState extends BaseState {
2024 
2025             private boolean mIsDisablingDueToAirplaneMode;
2026 
2027             @Override
enter()2028             public void enter() {
2029                 log("EnabledState.enter()");
2030                 super.enter();
2031                 if (!hasAnyModeManager()) {
2032                     Log.e(TAG, "Entered EnabledState, but no active mode managers");
2033                 }
2034                 mIsDisablingDueToAirplaneMode = false;
2035             }
2036 
2037             @Override
exit()2038             public void exit() {
2039                 log("EnabledState.exit()");
2040                 if (hasAnyModeManager()) {
2041                     Log.e(TAG, "Exiting EnabledState, but has active mode managers");
2042                 }
2043                 super.exit();
2044             }
2045 
2046             @Nullable
findAnyClientModeManagerConnectingOrConnectedToBssid( @onNull String ssid, @Nullable String bssid)2047             private ConcreteClientModeManager findAnyClientModeManagerConnectingOrConnectedToBssid(
2048                     @NonNull String ssid, @Nullable String bssid) {
2049                 if (bssid == null) {
2050                     return null;
2051                 }
2052                 for (ConcreteClientModeManager cmm : mClientModeManagers) {
2053                     if (isClientModeManagerConnectedOrConnectingToBssid(cmm, ssid, bssid)) {
2054                         return cmm;
2055                     }
2056                 }
2057                 return null;
2058             }
2059 
handleAdditionalClientModeManagerRequest( @onNull AdditionalClientModeManagerRequestInfo requestInfo)2060             private void handleAdditionalClientModeManagerRequest(
2061                     @NonNull AdditionalClientModeManagerRequestInfo requestInfo) {
2062                 ClientModeManager primaryManager = getPrimaryClientModeManagerNullable();
2063                 // TODO(b/228529090): Remove this special code once root cause is resolved.
2064                 // Special case for holders with ENTER_CAR_MODE_PRIORITIZED. Only give them the
2065                 // primary STA to avoid the device getting into STA+STA state.
2066                 // In STA+STA wifi scans will result in high latency in the secondary STA.
2067                 if (requestInfo.clientRole == ROLE_CLIENT_LOCAL_ONLY
2068                         && requestInfo.requestorWs != null) {
2069                     WorkSource workSource = requestInfo.requestorWs;
2070                     for (int i = 0; i < workSource.size(); i++) {
2071                         int curUid = workSource.getUid(i);
2072                         if (mWifiPermissionsUtil.checkEnterCarModePrioritized(curUid)) {
2073                             requestInfo.listener.onAnswer(primaryManager);
2074                             if (mVerboseLoggingEnabled) {
2075                                 Log.w(TAG, "Uid " + curUid
2076                                         + " has car mode permission - disabling STA+STA");
2077                             }
2078                             return;
2079                         }
2080                     }
2081                 }
2082                 if (requestInfo.clientRole == ROLE_CLIENT_SECONDARY_TRANSIENT
2083                         && mDppManager.isSessionInProgress()) {
2084                     // When MBB is triggered, we could end up switching the primary interface
2085                     // after completion. So if we have any DPP session in progress, they will fail
2086                     // when the previous primary iface is removed after MBB completion.
2087                     Log.v(TAG, "DPP session in progress, fallback to single STA behavior "
2088                             + "using primary ClientModeManager=" + primaryManager);
2089                     requestInfo.listener.onAnswer(primaryManager);
2090                     return;
2091                 }
2092                 ConcreteClientModeManager cmmForSameBssid =
2093                         findAnyClientModeManagerConnectingOrConnectedToBssid(
2094                                 requestInfo.ssid, requestInfo.bssid);
2095                 if (cmmForSameBssid != null) {
2096                     // Can't allow 2 client mode managers triggering connection to same bssid.
2097                     Log.v(TAG, "Already connected to bssid=" + requestInfo.bssid
2098                             + " on ClientModeManager=" + cmmForSameBssid);
2099                     if (cmmForSameBssid.getRole() == ROLE_CLIENT_PRIMARY) {
2100                         // fallback to single STA behavior.
2101                         requestInfo.listener.onAnswer(cmmForSameBssid);
2102                         return;
2103                     }
2104                     // The CMM having BSSID conflict is exactly the one being requested.
2105                     // Simply return the CMM in this case. The requestor will be responsible to
2106                     // make sure it does not trigger the connection again when already connected.
2107                     if (cmmForSameBssid.getRole() == requestInfo.clientRole) {
2108                         requestInfo.listener.onAnswer(cmmForSameBssid);
2109                         return;
2110                     }
2111                     // Existing secondary CMM connected to the same ssid/bssid.
2112                     if (!canRequestMoreClientModeManagersInRole(requestInfo.requestorWs,
2113                             requestInfo.clientRole, requestInfo.didUserApprove)) {
2114                         Log.e(TAG, "New request cannot override existing request on "
2115                                 + "ClientModeManager=" + cmmForSameBssid);
2116                         // If the new request does not have priority over the existing request,
2117                         // reject it since we cannot have 2 CMM's connected to same ssid/bssid.
2118                         requestInfo.listener.onAnswer(null);
2119                         return;
2120                     }
2121                     // If the new request has a higher priority over the existing one, change it's
2122                     // role and send it to the new client.
2123                     // Switch role for non primary CMM & wait for it to complete before
2124                     // handing it to the requestor.
2125                     switchRoleForAdditionalClientModeManager(
2126                             cmmForSameBssid, requestInfo.clientRole, requestInfo.listener,
2127                             requestInfo.requestorWs);
2128                     return;
2129                 }
2130 
2131                 ClientModeManager cmmForSameRole =
2132                         getClientModeManagerInRole(requestInfo.clientRole);
2133                 if (cmmForSameRole != null) {
2134                     // Already have a client mode manager in the requested role.
2135                     // Note: This logic results in the framework not supporting more than 1 CMM in
2136                     // the same role concurrently. There is no use-case for that currently &
2137                     // none of the clients (i.e WifiNetworkFactory, WifiConnectivityManager, etc)
2138                     // are ready to support that either. If this assumption changes in the future
2139                     // when the device supports 3 STA's for example, change this logic!
2140                     Log.v(TAG, "Already exists ClientModeManager for role: " + cmmForSameRole);
2141                     requestInfo.listener.onAnswer(cmmForSameRole);
2142                     return;
2143                 }
2144                 if (canRequestMoreClientModeManagersInRole(requestInfo.requestorWs,
2145                         requestInfo.clientRole, requestInfo.didUserApprove)) {
2146                     // Can create an additional client mode manager.
2147                     Log.v(TAG, "Starting a new ClientModeManager");
2148                     startAdditionalClientModeManager(
2149                             requestInfo.clientRole,
2150                             requestInfo.listener, requestInfo.requestorWs);
2151                     return;
2152                 }
2153 
2154                 // fallback decision
2155                 if (requestInfo.clientRole == ROLE_CLIENT_LOCAL_ONLY
2156                         && mContext.getResources().getBoolean(
2157                         R.bool.config_wifiMultiStaLocalOnlyConcurrencyEnabled)
2158                         && !mWifiPermissionsUtil.isTargetSdkLessThan(
2159                         requestInfo.requestorWs.getPackageName(0), Build.VERSION_CODES.S,
2160                         requestInfo.requestorWs.getUid(0))) {
2161                     Log.d(TAG, "Will not fall back to single STA for a local-only connection when "
2162                             + "STA+STA is supported (unless for a pre-S legacy app). "
2163                             + " Priority inversion.");
2164                     requestInfo.listener.onAnswer(null);
2165                     return;
2166                 }
2167 
2168                 // Fall back to single STA behavior.
2169                 Log.v(TAG, "Falling back to single STA behavior using primary ClientModeManager="
2170                         + primaryManager);
2171                 requestInfo.listener.onAnswer(primaryManager);
2172             }
2173 
2174             @Override
processMessageFiltered(Message msg)2175             public boolean processMessageFiltered(Message msg) {
2176                 switch (msg.what) {
2177                     case CMD_WIFI_TOGGLED:
2178                     case CMD_SCAN_ALWAYS_MODE_CHANGED:
2179                         handleStaToggleChangeInEnabledState((WorkSource) msg.obj);
2180                         break;
2181                     case CMD_REQUEST_ADDITIONAL_CLIENT_MODE_MANAGER:
2182                         handleAdditionalClientModeManagerRequest(
2183                                 (AdditionalClientModeManagerRequestInfo) msg.obj);
2184                         break;
2185                     case CMD_REMOVE_ADDITIONAL_CLIENT_MODE_MANAGER:
2186                         stopAdditionalClientModeManager((ClientModeManager) msg.obj);
2187                         break;
2188                     case CMD_SET_AP:
2189                         // note: CMD_SET_AP is handled/dropped in ECM mode - will not start here
2190                         if (msg.arg1 == 1) {
2191                             Pair<SoftApModeConfiguration, WorkSource> softApConfigAndWs =
2192                                     (Pair) msg.obj;
2193                             startSoftApModeManager(
2194                                     softApConfigAndWs.first, softApConfigAndWs.second);
2195                         } else {
2196                             stopSoftApModeManagers(msg.arg2);
2197                         }
2198                         break;
2199                     case CMD_AIRPLANE_TOGGLED:
2200                         // airplane mode toggled on is handled in the default state
2201                         if (mSettingsStore.isAirplaneModeOn()) {
2202                             mIsDisablingDueToAirplaneMode = true;
2203                             return NOT_HANDLED;
2204                         } else {
2205                             if (mIsDisablingDueToAirplaneMode) {
2206                                 // Previous airplane mode toggle on is being processed, defer the
2207                                 // message toggle off until previous processing is completed.
2208                                 // Once previous airplane mode toggle is complete, we should
2209                                 // transition to DisabledState. There, we will process the deferred
2210                                 // airplane mode toggle message to disable airplane mode.
2211                                 deferMessage(msg);
2212                             } else {
2213                                 // when airplane mode is toggled off, but wifi is on, we can keep it
2214                                 // on
2215                                 log("airplane mode toggled - and airplane mode is off. return "
2216                                         + "handled");
2217                             }
2218                             return HANDLED;
2219                         }
2220                     case CMD_AP_STOPPED:
2221                     case CMD_AP_START_FAILURE:
2222                         if (hasAnyModeManager()) {
2223                             log("AP disabled, remain in EnabledState.");
2224                             break;
2225                         }
2226                         if (msg.what == CMD_AP_STOPPED) {
2227                             mWifiInjector.getSelfRecovery().onWifiStopped();
2228                             if (mWifiInjector.getSelfRecovery().isRecoveryInProgress()) {
2229                                 // Recovery in progress, transit to disabled state.
2230                                 transitionTo(mDisabledState);
2231                                 break;
2232                             }
2233                         }
2234                         if (shouldEnableSta()) {
2235                             log("SoftAp disabled, start client mode");
2236                             startPrimaryOrScanOnlyClientModeManager(
2237                                     // Assumes user toggled it on from settings before.
2238                                     mFacade.getSettingsWorkSource(mContext));
2239                         } else {
2240                             log("SoftAp mode disabled, return to DisabledState");
2241                             transitionTo(mDisabledState);
2242                         }
2243                         break;
2244                     case CMD_STA_START_FAILURE:
2245                     case CMD_STA_STOPPED:
2246                         // Client mode stopped. Head to Disabled to wait for next command if there
2247                         // is no active mode manager.
2248                         if (!hasAnyModeManager()) {
2249                             mWifiInjector.getSelfRecovery().onWifiStopped();
2250                             log("STA disabled, return to DisabledState.");
2251                             transitionTo(mDisabledState);
2252                         } else {
2253                             log("STA disabled, remain in EnabledState.");
2254                         }
2255                         break;
2256                     case  CMD_DEFERRED_RECOVERY_RESTART_WIFI:
2257                         // Wifi shutdown is not completed yet, still in enabled state.
2258                         // Defer the message and wait for entering disabled state.
2259                         deferMessage(msg);
2260                         break;
2261                     case CMD_RECOVERY_RESTART_WIFI: {
2262                         final String bugTitle;
2263                         final String bugDetail = (String) msg.obj;
2264                         if (TextUtils.isEmpty(bugDetail)) {
2265                             bugTitle = "Wi-Fi BugReport";
2266                         } else {
2267                             bugTitle = "Wi-Fi BugReport: " + bugDetail;
2268                         }
2269                         log("Recovery triggered, disable wifi");
2270                         boolean bugReportRequested = msg.arg2 != 0;
2271                         if (bugReportRequested) {
2272                             mHandler.post(() ->
2273                                     mWifiDiagnostics.takeBugReport(bugTitle, bugDetail));
2274                         }
2275                         // Store all instances of tethered SAP + scan only/primary STA mode managers
2276                         List<ActiveModeManager> modeManagersBeforeRecovery = Stream.concat(
2277                                 mClientModeManagers.stream()
2278                                         .filter(m -> ROLE_CLIENT_SCAN_ONLY.equals(m.getRole())
2279                                                 || ROLE_CLIENT_PRIMARY.equals(m.getRole())),
2280                                 mSoftApManagers.stream()
2281                                         .filter(m -> ROLE_SOFTAP_TETHERED.equals(m.getRole())))
2282                                 .collect(Collectors.toList());
2283                         deferMessage(obtainMessage(CMD_DEFERRED_RECOVERY_RESTART_WIFI,
2284                                 modeManagersBeforeRecovery));
2285                         int numCallbacks = mRestartCallbacks.beginBroadcast();
2286                         for (int i = 0; i < numCallbacks; i++) {
2287                             try {
2288                                 mRestartCallbacks.getBroadcastItem(i).onSubsystemRestarting();
2289                             } catch (RemoteException e) {
2290                                 Log.e(TAG, "Failure calling onSubsystemRestarting" + e);
2291                             }
2292                         }
2293                         mRestartCallbacks.finishBroadcast();
2294                         shutdownWifi();
2295                         // onStopped will move the state machine to "DisabledState".
2296                         break;
2297                     }
2298                     default:
2299                         return NOT_HANDLED;
2300                 }
2301                 return HANDLED;
2302             }
2303         }
2304     }
2305 
coalesce(T a, T b)2306     private static <T> T coalesce(T a, T  b) {
2307         return a != null ? a : b;
2308     }
2309 
2310     /**
2311      * Check if CMM is connecting or connected to target BSSID and SSID
2312      */
isClientModeManagerConnectedOrConnectingToBssid( @onNull ClientModeManager clientModeManager, @NonNull String ssid, @NonNull String bssid)2313     public static boolean isClientModeManagerConnectedOrConnectingToBssid(
2314             @NonNull ClientModeManager clientModeManager,
2315             @NonNull String ssid, @NonNull String bssid) {
2316         WifiConfiguration connectedOrConnectingWifiConfiguration = coalesce(
2317                 clientModeManager.getConnectingWifiConfiguration(),
2318                 clientModeManager.getConnectedWifiConfiguration());
2319         String connectedOrConnectingBssid = coalesce(
2320                 clientModeManager.getConnectingBssid(),
2321                 clientModeManager.getConnectedBssid());
2322         String connectedOrConnectingSsid =
2323                 connectedOrConnectingWifiConfiguration == null
2324                         ? null : connectedOrConnectingWifiConfiguration.SSID;
2325         Log.v(TAG, connectedOrConnectingBssid + "   " + connectedOrConnectingSsid);
2326         return Objects.equals(ssid, connectedOrConnectingSsid)
2327                 && Objects.equals(bssid, connectedOrConnectingBssid);
2328     }
2329 }
2330