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