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