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