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