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