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.WIFI_STATE_ENABLED; 20 import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING; 21 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.net.ConnectivityManager; 27 import android.net.ConnectivityManager.NetworkCallback; 28 import android.net.DhcpResultsParcelable; 29 import android.net.Network; 30 import android.net.NetworkCapabilities; 31 import android.net.NetworkRequest; 32 import android.net.wifi.IWifiConnectedNetworkScorer; 33 import android.net.wifi.WifiAnnotations; 34 import android.net.wifi.WifiConfiguration; 35 import android.net.wifi.WifiInfo; 36 import android.net.wifi.WifiManager; 37 import android.net.wifi.hotspot2.IProvisioningCallback; 38 import android.net.wifi.hotspot2.OsuProvider; 39 import android.net.wifi.nl80211.DeviceWiphyCapabilities; 40 import android.os.Handler; 41 import android.os.IBinder; 42 import android.os.Looper; 43 import android.os.Message; 44 import android.os.PersistableBundle; 45 import android.os.UserHandle; 46 import android.os.WorkSource; 47 import android.telephony.AccessNetworkConstants; 48 import android.telephony.CarrierConfigManager; 49 import android.telephony.SubscriptionInfo; 50 import android.telephony.SubscriptionManager; 51 import android.telephony.ims.ImsException; 52 import android.telephony.ims.ImsMmTelManager; 53 import android.telephony.ims.ImsReasonInfo; 54 import android.telephony.ims.RegistrationManager; 55 import android.telephony.ims.feature.MmTelFeature; 56 import android.telephony.ims.stub.ImsRegistrationImplBase; 57 import android.text.TextUtils; 58 import android.util.Log; 59 60 import com.android.internal.util.IState; 61 import com.android.internal.util.State; 62 import com.android.internal.util.StateMachine; 63 import com.android.modules.utils.HandlerExecutor; 64 import com.android.server.wifi.WifiNative.InterfaceCallback; 65 import com.android.server.wifi.WifiNative.RxFateReport; 66 import com.android.server.wifi.WifiNative.TxFateReport; 67 import com.android.server.wifi.util.ActionListenerWrapper; 68 import com.android.server.wifi.util.StateMachineObituary; 69 import com.android.wifi.resources.R; 70 71 import java.io.FileDescriptor; 72 import java.io.PrintWriter; 73 import java.util.ArrayDeque; 74 import java.util.ArrayList; 75 import java.util.List; 76 import java.util.Set; 77 78 /** 79 * Manage WiFi in Client Mode where we connect to configured networks and in Scan Only Mode where 80 * we do not connect to configured networks but do perform scanning. 81 * 82 * An instance of this class is active to manage each client interface. This is in contrast to 83 * {@link DefaultClientModeManager} which handles calls when no client interfaces are active. 84 * 85 * This class will dynamically instantiate {@link ClientModeImpl} when it enters client mode, and 86 * tear it down when it exits client mode. No instance of ClientModeImpl will be active in 87 * scan-only mode, instead {@link ScanOnlyModeImpl} will be used to respond to calls. 88 * 89 * <pre> 90 * ActiveModeWarden 91 * / \ 92 * / \ 93 * ConcreteClientModeManager DefaultClientModeManager 94 * (Client Mode + Scan Only Mode) (Wifi off) 95 * / \ 96 * / \ 97 * ClientModeImpl ScanOnlyModeImpl 98 * </pre> 99 */ 100 public class ConcreteClientModeManager implements ClientModeManager { 101 private static final String TAG = "WifiClientModeManager"; 102 103 private final ClientModeStateMachine mStateMachine; 104 105 private final Context mContext; 106 private final Clock mClock; 107 private final WifiNative mWifiNative; 108 private final WifiMetrics mWifiMetrics; 109 private final WakeupController mWakeupController; 110 private final WifiInjector mWifiInjector; 111 private final SelfRecovery mSelfRecovery; 112 private final WifiGlobals mWifiGlobals; 113 private final DefaultClientModeManager mDefaultClientModeManager; 114 private final ClientModeManagerBroadcastQueue mBroadcastQueue; 115 private final long mId; 116 private final Graveyard mGraveyard = new Graveyard(); 117 118 private String mClientInterfaceName; 119 private boolean mIfaceIsUp = false; 120 private boolean mShouldReduceNetworkScore = false; 121 private final DeferStopHandler mDeferStopHandler; 122 @Nullable 123 private ClientRole mRole = null; 124 @Nullable 125 private ClientRole mPreviousRole = null; 126 private long mLastRoleChangeSinceBootMs = 0; 127 @Nullable 128 private WorkSource mRequestorWs = null; 129 @NonNull 130 private Listener<ConcreteClientModeManager> mModeListener; 131 /** Caches the latest role change request. This is needed for the IMS dereg delay */ 132 @Nullable 133 private RoleChangeInfo mTargetRoleChangeInfo; 134 private boolean mVerboseLoggingEnabled = false; 135 private int mActiveSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 136 private boolean mWifiStateChangeBroadcastEnabled = true; 137 private boolean mSecondaryInternet = false; 138 private boolean mIsDbs = false; 139 /** 140 * mClientModeImpl is only non-null when in {@link ClientModeStateMachine.ConnectModeState} - 141 * it will be null in all other states 142 */ 143 @Nullable 144 private ClientModeImpl mClientModeImpl = null; 145 146 @Nullable 147 private ScanOnlyModeImpl mScanOnlyModeImpl = null; 148 149 private boolean mIsStopped = true; 150 ConcreteClientModeManager( Context context, @NonNull Looper looper, Clock clock, WifiNative wifiNative, @NonNull Listener<ConcreteClientModeManager> listener, WifiMetrics wifiMetrics, WakeupController wakeupController, WifiInjector wifiInjector, SelfRecovery selfRecovery, WifiGlobals wifiGlobals, DefaultClientModeManager defaultClientModeManager, long id, @NonNull WorkSource requestorWs, @NonNull ClientRole role, @NonNull ClientModeManagerBroadcastQueue broadcastQueue, boolean verboseLoggingEnabled)151 ConcreteClientModeManager( 152 Context context, @NonNull Looper looper, Clock clock, 153 WifiNative wifiNative, @NonNull Listener<ConcreteClientModeManager> listener, 154 WifiMetrics wifiMetrics, 155 WakeupController wakeupController, WifiInjector wifiInjector, 156 SelfRecovery selfRecovery, WifiGlobals wifiGlobals, 157 DefaultClientModeManager defaultClientModeManager, long id, 158 @NonNull WorkSource requestorWs, @NonNull ClientRole role, 159 @NonNull ClientModeManagerBroadcastQueue broadcastQueue, 160 boolean verboseLoggingEnabled) { 161 mContext = context; 162 mClock = clock; 163 mWifiNative = wifiNative; 164 mModeListener = listener; 165 mWifiMetrics = wifiMetrics; 166 mWakeupController = wakeupController; 167 mWifiInjector = wifiInjector; 168 mStateMachine = new ClientModeStateMachine(looper); 169 mDeferStopHandler = new DeferStopHandler(looper); 170 mSelfRecovery = selfRecovery; 171 mWifiGlobals = wifiGlobals; 172 mDefaultClientModeManager = defaultClientModeManager; 173 mId = id; 174 mTargetRoleChangeInfo = new RoleChangeInfo(role, requestorWs, listener); 175 mBroadcastQueue = broadcastQueue; 176 enableVerboseLogging(verboseLoggingEnabled); 177 mStateMachine.sendMessage(ClientModeStateMachine.CMD_START, mTargetRoleChangeInfo); 178 } 179 getTag()180 private String getTag() { 181 return TAG + "[" + (mClientInterfaceName == null ? "unknown" : mClientInterfaceName) + "]"; 182 } 183 184 /** 185 * Sets whether to send WIFI_STATE_CHANGED broadcast for this ClientModeManager. 186 * @param enabled 187 */ setWifiStateChangeBroadcastEnabled(boolean enabled)188 public void setWifiStateChangeBroadcastEnabled(boolean enabled) { 189 mWifiStateChangeBroadcastEnabled = enabled; 190 } 191 192 /** 193 * Sets whether this ClientModeManager is for secondary STA with internet. 194 * @param secondaryInternet whether the ClientModeManager is for secondary internet. 195 */ setSecondaryInternet(boolean secondaryInternet)196 public void setSecondaryInternet(boolean secondaryInternet) { 197 // TODO: b/197670907 : Add client role ROLE_CLIENT_SECONDARY_INTERNET 198 if (mRole == ROLE_CLIENT_SECONDARY_LONG_LIVED) { 199 mSecondaryInternet = secondaryInternet; 200 } 201 } 202 203 /** 204 * Sets whether this ClientModeManager is for DBS AP multi internet. 205 * @param isDbs whether the ClientModeManager is connecting to to the same SSID as primary. 206 */ setSecondaryInternetDbsAp(boolean isDbs)207 public void setSecondaryInternetDbsAp(boolean isDbs) { 208 // TODO: b/197670907 : Add client role ROLE_CLIENT_SECONDARY_INTERNET 209 if (mRole == ROLE_CLIENT_SECONDARY_LONG_LIVED) { 210 mIsDbs = isDbs; 211 } 212 } 213 214 /** 215 * Returns whether this ClientModeManager is for secondary STA with internet. 216 * @return true if it is for secondary STA with internet. 217 */ isSecondaryInternet()218 public boolean isSecondaryInternet() { 219 return mSecondaryInternet; 220 } 221 222 /** 223 * Returns whether this ClientModeManager is for DBS AP multi internet. 224 * @return true if the ClientModeManager is connecting to to the same SSID as primary. 225 */ isSecondaryInternetDbsAp()226 public boolean isSecondaryInternetDbsAp() { 227 if (!isSecondaryInternet()) { 228 Log.wtf(TAG, "isSecondaryInternetDbsAp called while not secondary internet!?"); 229 (new Throwable()).printStackTrace(); 230 } 231 return mIsDbs; 232 } 233 234 /** 235 * Disconnect from any currently connected networks and stop client mode. 236 */ 237 @Override stop()238 public void stop() { 239 Log.d(getTag(), " currentstate: " + getCurrentStateName()); 240 mTargetRoleChangeInfo = null; 241 if (mIfaceIsUp) { 242 updateConnectModeState(mRole, WifiManager.WIFI_STATE_DISABLING, 243 WifiManager.WIFI_STATE_ENABLED); 244 } else { 245 updateConnectModeState(mRole, WifiManager.WIFI_STATE_DISABLING, 246 WifiManager.WIFI_STATE_ENABLING); 247 } 248 mDeferStopHandler.start(getWifiOffDeferringTimeMs()); 249 } 250 251 private class DeferStopHandler extends Handler { 252 private boolean mIsDeferring = false; 253 private ImsMmTelManager mImsMmTelManager = null; 254 private Looper mLooper = null; 255 private final Runnable mRunnable = () -> continueToStopWifi(); 256 private int mMaximumDeferringTimeMillis = 0; 257 private long mDeferringStartTimeMillis = 0; 258 private ConnectivityManager mConnectivityManager = null; 259 private List<ImsNetworkCallback> mImsNetworks = new ArrayList<>(); 260 private boolean mIsImsNetworkUnregistered = false; 261 262 private final RegistrationManager.RegistrationCallback mImsRegistrationCallback = 263 new RegistrationManager.RegistrationCallback() { 264 @Override 265 public void onRegistered(int imsRadioTech) { 266 Log.d(getTag(), "on IMS registered on type " + imsRadioTech); 267 if (!mIsDeferring) return; 268 269 if (imsRadioTech != AccessNetworkConstants.TRANSPORT_TYPE_WLAN) { 270 continueToStopWifi(); 271 } 272 } 273 274 @Override 275 public void onUnregistered(ImsReasonInfo imsReasonInfo) { 276 Log.d(getTag(), "on IMS unregistered"); 277 mIsImsNetworkUnregistered = true; 278 checkAndContinueToStopWifi(); 279 } 280 }; 281 282 private final class ImsNetworkCallback extends NetworkCallback { 283 private final int mNetworkType; 284 private int mRegisteredImsNetworkCount = 0; 285 286 /** 287 * Constructor for ImsNetworkCallback. 288 * 289 * @param type One of android.net.NetworkCapabilities.NetCapability. 290 */ ImsNetworkCallback(int type)291 ImsNetworkCallback(int type) { 292 mNetworkType = type; 293 } 294 295 @Override onAvailable(Network network)296 public void onAvailable(Network network) { 297 synchronized (this) { 298 Log.d(getTag(), "IMS network available: " + network 299 + ", type: " + mNetworkType); 300 mRegisteredImsNetworkCount++; 301 } 302 } 303 304 @Override onLost(Network network)305 public void onLost(Network network) { 306 synchronized (this) { 307 Log.d(getTag(), "IMS network lost: " + network 308 + " ,isDeferring: " + mIsDeferring 309 + " ,registered IMS network count: " + mRegisteredImsNetworkCount 310 + ", type: " + mNetworkType); 311 mRegisteredImsNetworkCount--; 312 if (mIsDeferring && mRegisteredImsNetworkCount <= 0) { 313 mRegisteredImsNetworkCount = 0; 314 checkAndContinueToStopWifi(); 315 } 316 } 317 } 318 isNetworkLost()319 public boolean isNetworkLost() { 320 return 0 == mRegisteredImsNetworkCount; 321 } 322 } 323 DeferStopHandler(Looper looper)324 DeferStopHandler(Looper looper) { 325 super(looper); 326 mLooper = looper; 327 mConnectivityManager = mContext.getSystemService(ConnectivityManager.class); 328 } 329 start(int delayMs)330 public void start(int delayMs) { 331 if (mIsDeferring) return; 332 333 mMaximumDeferringTimeMillis = delayMs; 334 mDeferringStartTimeMillis = mClock.getElapsedSinceBootMillis(); 335 // Most cases don't need delay, check it first to avoid unnecessary work. 336 if (delayMs == 0) { 337 continueToStopWifi(); 338 return; 339 } 340 341 mImsMmTelManager = ImsMmTelManager.createForSubscriptionId(mActiveSubId); 342 if (mImsMmTelManager == null || !postDelayed(mRunnable, delayMs)) { 343 // if no delay or failed to add runnable, stop Wifi immediately. 344 continueToStopWifi(); 345 return; 346 } 347 348 mIsDeferring = true; 349 Log.d(getTag(), "Start DeferWifiOff handler with deferring time " 350 + delayMs + " ms for subId: " + mActiveSubId); 351 try { 352 mImsMmTelManager.registerImsRegistrationCallback( 353 new HandlerExecutor(new Handler(mLooper)), 354 mImsRegistrationCallback); 355 } catch (RuntimeException | ImsException e) { 356 Log.e(getTag(), "registerImsRegistrationCallback failed", e); 357 continueToStopWifi(); 358 return; 359 } 360 361 registerImsNetworkCallback(NetworkCapabilities.NET_CAPABILITY_IMS); 362 registerImsNetworkCallback(NetworkCapabilities.NET_CAPABILITY_EIMS); 363 } 364 registerImsNetworkCallback(int imsType)365 private void registerImsNetworkCallback(int imsType) { 366 NetworkRequest imsRequest = new NetworkRequest.Builder() 367 .addCapability(imsType) 368 .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) 369 .build(); 370 ImsNetworkCallback imsCallback = new ImsNetworkCallback(imsType); 371 mConnectivityManager.registerNetworkCallback(imsRequest, imsCallback, 372 new Handler(mLooper)); 373 mImsNetworks.add(imsCallback); 374 } 375 checkAndContinueToStopWifi()376 private void checkAndContinueToStopWifi() { 377 if (!mIsImsNetworkUnregistered) return; 378 379 for (ImsNetworkCallback c: mImsNetworks) { 380 if (!c.isNetworkLost()) return; 381 } 382 383 // Add delay for targets where IMS PDN down at modem takes additional delay. 384 int delay = mContext.getResources() 385 .getInteger(R.integer.config_wifiDelayDisconnectOnImsLostMs); 386 if (delay == 0 || !postDelayed(mRunnable, delay)) { 387 continueToStopWifi(); 388 } 389 } 390 continueToStopWifi()391 private void continueToStopWifi() { 392 Log.d(getTag(), "The target role change info " + mTargetRoleChangeInfo); 393 394 int deferringDurationMillis = 395 (int) (mClock.getElapsedSinceBootMillis() - mDeferringStartTimeMillis); 396 boolean isTimedOut = mMaximumDeferringTimeMillis > 0 397 && deferringDurationMillis >= mMaximumDeferringTimeMillis; 398 if (mTargetRoleChangeInfo == null) { 399 Log.d(getTag(), "Continue to stop wifi"); 400 mStateMachine.captureObituaryAndQuitNow(); 401 mWifiMetrics.noteWifiOff(mIsDeferring, isTimedOut, deferringDurationMillis); 402 } else if (mTargetRoleChangeInfo.role == ROLE_CLIENT_SCAN_ONLY) { 403 if (!mWifiNative.switchClientInterfaceToScanMode( 404 mClientInterfaceName, mTargetRoleChangeInfo.requestorWs)) { 405 mModeListener.onStartFailure(ConcreteClientModeManager.this); 406 } else { 407 mStateMachine.sendMessage( 408 ClientModeStateMachine.CMD_SWITCH_TO_SCAN_ONLY_MODE_CONTINUE, 409 mTargetRoleChangeInfo); 410 mWifiMetrics.noteWifiOff(mIsDeferring, isTimedOut, deferringDurationMillis); 411 } 412 } else { 413 updateConnectModeState(mRole, WifiManager.WIFI_STATE_ENABLED, 414 WifiManager.WIFI_STATE_DISABLING); 415 } 416 417 if (!mIsDeferring) return; 418 419 Log.d(getTag(), "Stop DeferWifiOff handler."); 420 removeCallbacks(mRunnable); 421 if (mImsMmTelManager != null) { 422 try { 423 mImsMmTelManager.unregisterImsRegistrationCallback(mImsRegistrationCallback); 424 } catch (RuntimeException e) { 425 Log.e(getTag(), "unregisterImsRegistrationCallback failed", e); 426 } 427 } 428 429 if (mConnectivityManager != null && mImsNetworks.size() > 0) { 430 for (ImsNetworkCallback c: mImsNetworks) { 431 mConnectivityManager.unregisterNetworkCallback(c); 432 } 433 mImsNetworks.clear(); 434 } 435 436 mIsDeferring = false; 437 mIsImsNetworkUnregistered = false; 438 } 439 } 440 441 /** 442 * Get deferring time before turning off WiFi. 443 */ getWifiOffDeferringTimeMs()444 private int getWifiOffDeferringTimeMs() { 445 SubscriptionManager subscriptionManager = 446 mContext.getSystemService(SubscriptionManager.class); 447 if (subscriptionManager == null) { 448 Log.d(getTag(), "SubscriptionManager not found"); 449 return 0; 450 } 451 452 List<SubscriptionInfo> subInfoList = subscriptionManager.getActiveSubscriptionInfoList(); 453 if (subInfoList == null) { 454 Log.d(getTag(), "Active SubscriptionInfo list not found"); 455 return 0; 456 } 457 458 // Get the maximum delay for the active subscription latched on IWLAN. 459 int maxDelay = 0; 460 for (SubscriptionInfo subInfo : subInfoList) { 461 int curDelay = getWifiOffDeferringTimeMs(subInfo.getSubscriptionId()); 462 if (curDelay > maxDelay) { 463 maxDelay = curDelay; 464 mActiveSubId = subInfo.getSubscriptionId(); 465 } 466 } 467 return maxDelay; 468 } 469 getWifiOffDeferringTimeMs(int subId)470 private int getWifiOffDeferringTimeMs(int subId) { 471 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 472 Log.d(getTag(), "Invalid Subscription ID: " + subId); 473 return 0; 474 } 475 476 ImsMmTelManager imsMmTelManager = ImsMmTelManager.createForSubscriptionId(subId); 477 // If no wifi calling, no delay 478 try { 479 if (!imsMmTelManager.isAvailable( 480 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE, 481 ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN)) { 482 Log.d(getTag(), "IMS not registered over IWLAN for subId: " + subId); 483 return 0; 484 } 485 } catch (RuntimeException ex) { 486 Log.e(TAG, "IMS Manager is not available.", ex); 487 return 0; 488 } 489 490 CarrierConfigManager configManager = mContext.getSystemService(CarrierConfigManager.class); 491 PersistableBundle config = configManager.getConfigForSubId(subId); 492 return (config != null) 493 ? config.getInt(CarrierConfigManager.Ims.KEY_WIFI_OFF_DEFERRING_TIME_MILLIS_INT) 494 : 0; 495 } 496 497 @Override getRole()498 @Nullable public ClientRole getRole() { 499 return mRole; 500 } 501 502 /** 503 * Get the role this ClientModeManager is expected to become. 504 */ getTargetRole()505 @Nullable public ClientRole getTargetRole() { 506 return mTargetRoleChangeInfo == null ? null : mTargetRoleChangeInfo.role; 507 } 508 509 @Override getPreviousRole()510 @Nullable public ClientRole getPreviousRole() { 511 return mPreviousRole; 512 } 513 514 @Override getLastRoleChangeSinceBootMs()515 public long getLastRoleChangeSinceBootMs() { 516 return mLastRoleChangeSinceBootMs; 517 } 518 519 /** 520 * Class to hold info needed for role change. 521 */ 522 private static class RoleChangeInfo { 523 @Nullable public final ClientRole role; 524 @Nullable public final WorkSource requestorWs; 525 @Nullable public final Listener<ConcreteClientModeManager> modeListener; 526 RoleChangeInfo(@ullable ClientRole role)527 RoleChangeInfo(@Nullable ClientRole role) { 528 this(role, null, null); 529 } 530 RoleChangeInfo(@ullable ClientRole role, @Nullable WorkSource requestorWs, @Nullable Listener<ConcreteClientModeManager> modeListener)531 RoleChangeInfo(@Nullable ClientRole role, @Nullable WorkSource requestorWs, 532 @Nullable Listener<ConcreteClientModeManager> modeListener) { 533 this.role = role; 534 this.requestorWs = requestorWs; 535 this.modeListener = modeListener; 536 } 537 538 @Override toString()539 public String toString() { 540 return "Role: " + role + ", RequestorWs: " + requestorWs 541 + ", ModeListener: " + modeListener; 542 } 543 } 544 545 /** Set the role of this ClientModeManager */ setRole(@onNull ClientRole role, @NonNull WorkSource requestorWs)546 public void setRole(@NonNull ClientRole role, @NonNull WorkSource requestorWs) { 547 setRole(role, requestorWs, null); 548 } 549 550 /** Set the role of this ClientModeManager */ setRole(@onNull ClientRole role, @NonNull WorkSource requestorWs, @Nullable Listener<ConcreteClientModeManager> modeListener)551 public void setRole(@NonNull ClientRole role, @NonNull WorkSource requestorWs, 552 @Nullable Listener<ConcreteClientModeManager> modeListener) { 553 mTargetRoleChangeInfo = new RoleChangeInfo(role, requestorWs, modeListener); 554 if (role == ROLE_CLIENT_SCAN_ONLY) { 555 // Switch client mode manager to scan only mode. 556 mStateMachine.sendMessage( 557 ClientModeStateMachine.CMD_SWITCH_TO_SCAN_ONLY_MODE); 558 } else { 559 // Switch client mode manager to connect mode. 560 mStateMachine.sendMessage( 561 ClientModeStateMachine.CMD_SWITCH_TO_CONNECT_MODE, 562 mTargetRoleChangeInfo); 563 } 564 } 565 566 @Override getInterfaceName()567 public String getInterfaceName() { 568 return mClientInterfaceName; 569 } 570 571 @Override getRequestorWs()572 public WorkSource getRequestorWs() { 573 return mRequestorWs; 574 } 575 576 /** 577 * Keep stopped {@link ClientModeImpl} instances so that they can be dumped to aid debugging. 578 * 579 * TODO(b/160283853): Find a smarter way to evict old ClientModeImpls 580 */ 581 private static class Graveyard { 582 private static final int INSTANCES_TO_KEEP = 3; 583 584 private final ArrayDeque<ClientModeImpl> mClientModeImpls = new ArrayDeque<>(); 585 586 /** 587 * Add this stopped {@link ClientModeImpl} to the graveyard, and evict the oldest 588 * ClientModeImpl if the graveyard is full. 589 */ inter(ClientModeImpl clientModeImpl)590 void inter(ClientModeImpl clientModeImpl) { 591 if (mClientModeImpls.size() == INSTANCES_TO_KEEP) { 592 mClientModeImpls.removeFirst(); 593 } 594 mClientModeImpls.addLast(clientModeImpl); 595 } 596 597 /** Dump the contents of the graveyard. */ dump(FileDescriptor fd, PrintWriter pw, String[] args)598 void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 599 pw.println("Dump of ConcreteClientModeManager.Graveyard"); 600 pw.println("Stopped ClientModeImpls: " + mClientModeImpls.size() + " total"); 601 for (ClientModeImpl clientModeImpl : mClientModeImpls) { 602 clientModeImpl.dump(fd, pw, args); 603 } 604 pw.println(); 605 } 606 hasAllClientModeImplsQuit()607 boolean hasAllClientModeImplsQuit() { 608 for (ClientModeImpl cmi : mClientModeImpls) { 609 if (!cmi.hasQuit()) return false; 610 } 611 return true; 612 } 613 } 614 615 /** 616 * Dump info about this ClientMode manager. 617 */ 618 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)619 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 620 pw.println("Dump of ClientModeManager id=" + mId); 621 pw.println("current StateMachine mode: " + getCurrentStateName()); 622 pw.println("mRole: " + mRole); 623 pw.println("mPreviousRole: " + mPreviousRole); 624 pw.println("mTargetRoleChangeInfo: " + mTargetRoleChangeInfo); 625 pw.println("mClientInterfaceName: " + mClientInterfaceName); 626 pw.println("mIfaceIsUp: " + mIfaceIsUp); 627 pw.println("mSecondaryInternet: " + mSecondaryInternet); 628 pw.println("mIsDbs: " + mIsDbs); 629 mStateMachine.dump(fd, pw, args); 630 pw.println(); 631 if (mClientModeImpl == null) { 632 pw.println("No active ClientModeImpl instance"); 633 } else { 634 mClientModeImpl.dump(fd, pw, args); 635 } 636 mGraveyard.dump(fd, pw, args); 637 pw.println(); 638 } 639 getCurrentStateName()640 private String getCurrentStateName() { 641 IState currentState = mStateMachine.getCurrentState(); 642 643 if (currentState != null) { 644 return currentState.getName(); 645 } 646 647 return "StateMachine not active"; 648 } 649 650 /** 651 * Update Wifi state and send the broadcast. 652 * 653 * @param role Target/Set role for this client mode manager instance. 654 * @param newState new Wifi state 655 * @param currentState current wifi state 656 */ updateConnectModeState(ClientRole role, int newState, int currentState)657 private void updateConnectModeState(ClientRole role, int newState, int currentState) { 658 if (role != ROLE_CLIENT_PRIMARY || !mWifiStateChangeBroadcastEnabled) { 659 // do not raise public broadcast unless this is the primary client mode manager 660 return; 661 } 662 // TODO(b/186881160): May need to restore per STA state for Battery state reported. 663 mWifiInjector.getActiveModeWarden().setWifiStateForApiCalls(newState); 664 if (newState == WifiManager.WIFI_STATE_UNKNOWN) { 665 // do not need to broadcast failure to system 666 return; 667 } 668 669 // TODO(b/175839153): this broadcast should only be sent out when wifi is toggled on/off, 670 // not per CMM 671 final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION); 672 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 673 intent.putExtra(WifiManager.EXTRA_WIFI_STATE, newState); 674 intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, currentState); 675 String summary = "broadcast=WIFI_STATE_CHANGED_ACTION" 676 + " EXTRA_WIFI_STATE=" + newState 677 + " EXTRA_PREVIOUS_WIFI_STATE=" + currentState; 678 if (mVerboseLoggingEnabled) Log.d(getTag(), "Queuing " + summary); 679 ClientModeManagerBroadcastQueue.QueuedBroadcast broadcast = 680 () -> { 681 if (mVerboseLoggingEnabled) Log.d(getTag(), "Sending " + summary); 682 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 683 }; 684 if (mRole == null && role == ROLE_CLIENT_PRIMARY) { 685 // This CMM is intended to be the primary, but has not completed the mode transition 686 // yet. Need to force broadcast to be sent. 687 broadcast.send(); 688 } else { 689 mBroadcastQueue.queueOrSendBroadcast(this, broadcast); 690 } 691 } 692 693 private class ClientModeStateMachine extends StateMachine { 694 // Commands for the state machine. 695 public static final int CMD_START = 0; 696 public static final int CMD_SWITCH_TO_SCAN_ONLY_MODE = 1; 697 public static final int CMD_SWITCH_TO_CONNECT_MODE = 2; 698 public static final int CMD_INTERFACE_STATUS_CHANGED = 3; 699 public static final int CMD_INTERFACE_DESTROYED = 4; 700 public static final int CMD_INTERFACE_DOWN = 5; 701 public static final int CMD_SWITCH_TO_SCAN_ONLY_MODE_CONTINUE = 6; 702 private final State mIdleState = new IdleState(); 703 private final State mStartedState = new StartedState(); 704 private final State mScanOnlyModeState = new ScanOnlyModeState(); 705 private final State mConnectModeState = new ConnectModeState(); 706 // Workaround since we cannot use transitionTo(mScanOnlyModeState, RoleChangeInfo) 707 private RoleChangeInfo mScanRoleChangeInfoToSetOnTransition = null; 708 // Workaround since we cannot use transitionTo(mConnectModeState, RoleChangeInfo) 709 private RoleChangeInfo mConnectRoleChangeInfoToSetOnTransition = null; 710 711 @Nullable 712 private StateMachineObituary mObituary = null; 713 714 private final InterfaceCallback mWifiNativeInterfaceCallback = new InterfaceCallback() { 715 @Override 716 public void onDestroyed(String ifaceName) { 717 if (mClientInterfaceName != null && mClientInterfaceName.equals(ifaceName)) { 718 Log.d(getTag(), "STA iface " + ifaceName + " was destroyed, " 719 + "stopping client mode"); 720 721 // we must immediately clean up state in ClientModeImpl to unregister 722 // all client mode related objects 723 // Note: onDestroyed is only called from the main Wifi thread 724 if (mClientModeImpl == null) { 725 Log.w(getTag(), "Received mWifiNativeInterfaceCallback.onDestroyed " 726 + "callback when no ClientModeImpl instance is active."); 727 } else { 728 mClientModeImpl.handleIfaceDestroyed(); 729 } 730 731 sendMessage(CMD_INTERFACE_DESTROYED); 732 } 733 } 734 735 @Override 736 public void onUp(String ifaceName) { 737 if (mClientInterfaceName != null && mClientInterfaceName.equals(ifaceName)) { 738 sendMessage(CMD_INTERFACE_STATUS_CHANGED, 1); 739 } 740 } 741 742 @Override 743 public void onDown(String ifaceName) { 744 if (mClientInterfaceName != null && mClientInterfaceName.equals(ifaceName)) { 745 sendMessage(CMD_INTERFACE_STATUS_CHANGED, 0); 746 } 747 } 748 }; 749 ClientModeStateMachine(Looper looper)750 ClientModeStateMachine(Looper looper) { 751 super(TAG, looper); 752 753 // CHECKSTYLE:OFF IndentationCheck 754 addState(mIdleState); 755 addState(mStartedState, mIdleState); 756 addState(mScanOnlyModeState, mStartedState); 757 addState(mConnectModeState, mStartedState); 758 // CHECKSTYLE:ON IndentationCheck 759 760 setInitialState(mIdleState); 761 start(); 762 } 763 captureObituaryAndQuitNow()764 void captureObituaryAndQuitNow() { 765 // capture StateMachine LogRecs since we will lose them after we call quitNow() 766 // This is used for debugging. 767 mObituary = new StateMachineObituary(this); 768 769 quitNow(); 770 } 771 772 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)773 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 774 if (mObituary == null) { 775 // StateMachine hasn't quit yet, dump `this` via StateMachineObituary's dump() 776 // method for consistency with `else` branch. 777 new StateMachineObituary(this).dump(fd, pw, args); 778 } else { 779 // StateMachine has quit and cleared all LogRecs. 780 // Get them from the obituary instead. 781 mObituary.dump(fd, pw, args); 782 } 783 } 784 785 /** 786 * Reset this ConcreteClientModeManager when its role changes, so that it can be reused for 787 * another purpose. 788 */ reset()789 private void reset() { 790 // Therefore, the caller must ensure that the role change has been completed and these 791 // settings have already reset before setting them, otherwise the new setting would be 792 // lost. 793 setShouldReduceNetworkScore(false); 794 } 795 setRoleInternal(@onNull RoleChangeInfo roleChangeInfo)796 private void setRoleInternal(@NonNull RoleChangeInfo roleChangeInfo) { 797 mPreviousRole = mRole; 798 mLastRoleChangeSinceBootMs = mClock.getElapsedSinceBootMillis(); 799 mRole = roleChangeInfo.role; 800 if (roleChangeInfo.requestorWs != null) { 801 mRequestorWs = roleChangeInfo.requestorWs; 802 } 803 if (roleChangeInfo.modeListener != null) { 804 mModeListener = roleChangeInfo.modeListener; 805 } 806 } 807 setRoleInternalAndInvokeCallback(@onNull RoleChangeInfo roleChangeInfo)808 private void setRoleInternalAndInvokeCallback(@NonNull RoleChangeInfo roleChangeInfo) { 809 if (roleChangeInfo.role == mRole) return; 810 if (mRole == null) { 811 Log.v(getTag(), "ClientModeManager started in role: " + roleChangeInfo); 812 setRoleInternal(roleChangeInfo); 813 mModeListener.onStarted(ConcreteClientModeManager.this); 814 } else { 815 Log.v(getTag(), "ClientModeManager role changed: " + roleChangeInfo); 816 setRoleInternal(roleChangeInfo); 817 reset(); 818 mModeListener.onRoleChanged(ConcreteClientModeManager.this); 819 } 820 if (mClientModeImpl != null) { 821 mClientModeImpl.onRoleChanged(); 822 } 823 } 824 825 private class IdleState extends State { 826 @Override enter()827 public void enter() { 828 Log.d(getTag(), "entering IdleState"); 829 mClientInterfaceName = null; 830 mIfaceIsUp = false; 831 } 832 833 @Override exit()834 public void exit() { 835 // Sometimes the wifi handler thread may become blocked that the statemachine 836 // will exit in the IdleState without first entering StartedState. Trigger a 837 // cleanup here in case the above sequence happens. This the statemachine was 838 // started normally this will will not send a duplicate broadcast since mIsStopped 839 // will get set to false the first time the exit happens. 840 cleanupOnQuitIfApplicable(); 841 } 842 843 @Override processMessage(Message message)844 public boolean processMessage(Message message) { 845 switch (message.what) { 846 case CMD_START: 847 // Always start in scan mode first. 848 RoleChangeInfo roleChangeInfo = (RoleChangeInfo) message.obj; 849 mClientInterfaceName = mWifiNative.setupInterfaceForClientInScanMode( 850 mWifiNativeInterfaceCallback, roleChangeInfo.requestorWs); 851 if (TextUtils.isEmpty(mClientInterfaceName)) { 852 Log.e(getTag(), "Failed to create ClientInterface. Sit in Idle"); 853 takeBugReportInterfaceFailureIfNeeded( 854 "Wi-Fi scan STA interface HAL failure"); 855 mModeListener.onStartFailure(ConcreteClientModeManager.this); 856 break; 857 } 858 if (roleChangeInfo.role instanceof ClientConnectivityRole) { 859 sendMessage(CMD_SWITCH_TO_CONNECT_MODE, roleChangeInfo); 860 transitionTo(mStartedState); 861 } else { 862 mScanRoleChangeInfoToSetOnTransition = roleChangeInfo; 863 transitionTo(mScanOnlyModeState); 864 } 865 break; 866 default: 867 Log.d(getTag(), "received an invalid message: " + message); 868 return NOT_HANDLED; 869 } 870 return HANDLED; 871 } 872 } 873 874 private class StartedState extends State { 875 onUpChanged(boolean isUp)876 private void onUpChanged(boolean isUp) { 877 if (isUp == mIfaceIsUp) { 878 return; // no change 879 } 880 mIfaceIsUp = isUp; 881 if (!isUp) { 882 // if the interface goes down we should exit and go back to idle state. 883 Log.d(getTag(), "interface down!"); 884 mStateMachine.sendMessage(CMD_INTERFACE_DOWN); 885 } 886 if (mClientModeImpl != null) { 887 mClientModeImpl.onUpChanged(isUp); 888 } 889 } 890 891 @Override enter()892 public void enter() { 893 Log.d(getTag(), "entering StartedState"); 894 mIfaceIsUp = false; 895 mIsStopped = false; 896 onUpChanged(mWifiNative.isInterfaceUp(mClientInterfaceName)); 897 } 898 899 @Override processMessage(Message message)900 public boolean processMessage(Message message) { 901 switch (message.what) { 902 case CMD_START: 903 // Already started, ignore this command. 904 break; 905 case CMD_SWITCH_TO_CONNECT_MODE: { 906 RoleChangeInfo roleChangeInfo = (RoleChangeInfo) message.obj; 907 updateConnectModeState(roleChangeInfo.role, 908 WifiManager.WIFI_STATE_ENABLING, 909 WifiManager.WIFI_STATE_DISABLED); 910 if (!mWifiNative.switchClientInterfaceToConnectivityMode( 911 mClientInterfaceName, roleChangeInfo.requestorWs)) { 912 updateConnectModeState(roleChangeInfo.role, 913 WifiManager.WIFI_STATE_UNKNOWN, 914 WifiManager.WIFI_STATE_ENABLING); 915 updateConnectModeState(roleChangeInfo.role, 916 WifiManager.WIFI_STATE_DISABLED, 917 WifiManager.WIFI_STATE_UNKNOWN); 918 takeBugReportInterfaceFailureIfNeeded( 919 "Wi-Fi STA interface HAL failure"); 920 mModeListener.onStartFailure(ConcreteClientModeManager.this); 921 break; 922 } 923 // Role set in the enter of ConnectModeState. 924 mConnectRoleChangeInfoToSetOnTransition = roleChangeInfo; 925 transitionTo(mConnectModeState); 926 break; 927 } 928 case CMD_SWITCH_TO_SCAN_ONLY_MODE: 929 updateConnectModeState(mRole, WifiManager.WIFI_STATE_DISABLING, 930 WifiManager.WIFI_STATE_ENABLED); 931 mDeferStopHandler.start(getWifiOffDeferringTimeMs()); 932 break; 933 case CMD_SWITCH_TO_SCAN_ONLY_MODE_CONTINUE: { 934 RoleChangeInfo roleChangeInfo = (RoleChangeInfo) message.obj; 935 mScanRoleChangeInfoToSetOnTransition = roleChangeInfo; 936 transitionTo(mScanOnlyModeState); 937 break; 938 } 939 case CMD_INTERFACE_DOWN: 940 Log.e(getTag(), "Detected an interface down, reporting failure to " 941 + "SelfRecovery"); 942 mSelfRecovery.trigger(SelfRecovery.REASON_STA_IFACE_DOWN); 943 // once interface down, nothing else to do... stop the state machine 944 captureObituaryAndQuitNow(); 945 break; 946 case CMD_INTERFACE_STATUS_CHANGED: 947 boolean isUp = message.arg1 == 1; 948 onUpChanged(isUp); 949 break; 950 case CMD_INTERFACE_DESTROYED: 951 Log.e(getTag(), "interface destroyed - client mode stopping"); 952 mClientInterfaceName = null; 953 // once interface destroyed, nothing else to do... stop the state machine 954 captureObituaryAndQuitNow(); 955 break; 956 default: 957 return NOT_HANDLED; 958 } 959 return HANDLED; 960 } 961 962 /** 963 * Clean up state, unregister listeners and update wifi state. 964 */ 965 @Override exit()966 public void exit() { 967 if (mClientInterfaceName != null) { 968 mWifiNative.teardownInterface(mClientInterfaceName); 969 mClientInterfaceName = null; 970 mIfaceIsUp = false; 971 } 972 973 Log.i(getTag(), "StartedState#exit(), setting mRole = null"); 974 mIsStopped = true; 975 cleanupOnQuitIfApplicable(); 976 } 977 } 978 979 private class ScanOnlyModeState extends State { 980 @Override enter()981 public void enter() { 982 Log.d(getTag(), "entering ScanOnlyModeState"); 983 984 if (mClientInterfaceName != null) { 985 mScanOnlyModeImpl = mWifiInjector.makeScanOnlyModeImpl( 986 mClientInterfaceName); 987 } else { 988 Log.e(getTag(), "Entered ScanOnlyModeState with a null interface name!"); 989 } 990 991 if (mScanRoleChangeInfoToSetOnTransition == null 992 || (mScanRoleChangeInfoToSetOnTransition.role != ROLE_CLIENT_SCAN_ONLY)) { 993 Log.wtf(TAG, "Unexpected mScanRoleChangeInfoToSetOnTransition: " 994 + mScanRoleChangeInfoToSetOnTransition); 995 // Should never happen, but fallback to scan only to avoid a crash. 996 mScanRoleChangeInfoToSetOnTransition = 997 new RoleChangeInfo(ROLE_CLIENT_SCAN_ONLY); 998 } 999 1000 setRoleInternalAndInvokeCallback(mScanRoleChangeInfoToSetOnTransition); 1001 // If we're in ScanOnlyModeState, there is only 1 CMM. So it's ok to call 1002 // WakeupController directly, there won't be multiple CMMs trampling over each other 1003 mWakeupController.start(); 1004 mWifiNative.setScanMode(mClientInterfaceName, true); 1005 } 1006 1007 @Override processMessage(Message message)1008 public boolean processMessage(Message message) { 1009 switch (message.what) { 1010 case CMD_SWITCH_TO_SCAN_ONLY_MODE: 1011 // Already in scan only mode, ignore this command. 1012 break; 1013 default: 1014 return NOT_HANDLED; 1015 } 1016 return HANDLED; 1017 } 1018 1019 @Override exit()1020 public void exit() { 1021 mScanOnlyModeImpl = null; 1022 mScanRoleChangeInfoToSetOnTransition = null; 1023 1024 // If we're in ScanOnlyModeState, there is only 1 CMM. So it's ok to call 1025 // WakeupController directly, there won't be multiple CMMs trampling over each other 1026 mWakeupController.stop(); 1027 mWifiNative.setScanMode(mClientInterfaceName, false); 1028 } 1029 } 1030 1031 private class ConnectModeState extends State { 1032 @Override enter()1033 public void enter() { 1034 Log.d(getTag(), "entering ConnectModeState, starting ClientModeImpl"); 1035 if (mClientInterfaceName == null) { 1036 Log.e(getTag(), "Supposed to start ClientModeImpl, but iface is null!"); 1037 } else { 1038 if (mClientModeImpl != null) { 1039 Log.e(getTag(), "ConnectModeState.enter(): mClientModeImpl is already " 1040 + "instantiated?!"); 1041 } 1042 mClientModeImpl = mWifiInjector.makeClientModeImpl( 1043 mClientInterfaceName, ConcreteClientModeManager.this, 1044 mVerboseLoggingEnabled); 1045 mClientModeImpl.setShouldReduceNetworkScore(mShouldReduceNetworkScore); 1046 } 1047 if (mConnectRoleChangeInfoToSetOnTransition == null 1048 || !(mConnectRoleChangeInfoToSetOnTransition.role 1049 instanceof ClientConnectivityRole)) { 1050 Log.wtf(TAG, "Unexpected mConnectRoleChangeInfoToSetOnTransition: " 1051 + mConnectRoleChangeInfoToSetOnTransition); 1052 // Should never happen, but fallback to primary to avoid a crash. 1053 mConnectRoleChangeInfoToSetOnTransition = 1054 new RoleChangeInfo(ROLE_CLIENT_PRIMARY); 1055 } 1056 1057 // Could be any one of possible connect mode roles. 1058 setRoleInternalAndInvokeCallback(mConnectRoleChangeInfoToSetOnTransition); 1059 updateConnectModeState(mConnectRoleChangeInfoToSetOnTransition.role, 1060 WIFI_STATE_ENABLED, WIFI_STATE_ENABLING); 1061 } 1062 1063 @Override processMessage(Message message)1064 public boolean processMessage(Message message) { 1065 switch (message.what) { 1066 case CMD_SWITCH_TO_CONNECT_MODE: 1067 RoleChangeInfo roleChangeInfo = (RoleChangeInfo) message.obj; 1068 // switching to connect mode when already in connect mode, just update the 1069 // requestor WorkSource. 1070 boolean success = mWifiNative.replaceStaIfaceRequestorWs( 1071 mClientInterfaceName, roleChangeInfo.requestorWs); 1072 if (success) { 1073 setRoleInternalAndInvokeCallback(roleChangeInfo); 1074 } else { 1075 // If this call failed, the iface would be torn down. 1076 // Thus, simply abort and let the iface down handling take care of the 1077 // rest. 1078 Log.e(getTag(), "Failed to switch ClientModeManager=" 1079 + ConcreteClientModeManager.this + "'s requestorWs"); 1080 } 1081 break; 1082 case CMD_SWITCH_TO_SCAN_ONLY_MODE: 1083 case CMD_INTERFACE_DESTROYED: 1084 updateConnectModeState(mRole, WifiManager.WIFI_STATE_DISABLING, 1085 WifiManager.WIFI_STATE_ENABLED); 1086 return NOT_HANDLED; // Handled in StartedState. 1087 case CMD_INTERFACE_DOWN: 1088 updateConnectModeState(mRole, WifiManager.WIFI_STATE_DISABLING, 1089 WifiManager.WIFI_STATE_UNKNOWN); 1090 return NOT_HANDLED; // Handled in StartedState. 1091 case CMD_INTERFACE_STATUS_CHANGED: 1092 boolean isUp = message.arg1 == 1; 1093 if (isUp == mIfaceIsUp) { 1094 break; // no change 1095 } 1096 if (!isUp) { 1097 // TODO(b/201584491) Figure out what to do with this block of code 1098 // handling iface down since most devices should have MAC randomization 1099 // enabled, which makes the "else" block essentially no-op. Also, the 1100 // "else" block would actually fully disable wifi which is not desirable 1101 // behavior because the firmware can recover the iface after it is down. 1102 if (mWifiGlobals.isConnectedMacRandomizationEnabled()) { 1103 return HANDLED; // For MAC randomization, ignore... 1104 } else { 1105 // Handle the error case where our underlying interface went down if 1106 // we do not have mac randomization enabled (b/72459123). 1107 // if the interface goes down we should exit and go back to idle 1108 // state. 1109 updateConnectModeState(mRole, WifiManager.WIFI_STATE_UNKNOWN, 1110 WifiManager.WIFI_STATE_ENABLED); 1111 } 1112 } 1113 return NOT_HANDLED; // Handled in StartedState. 1114 default: 1115 return NOT_HANDLED; 1116 } 1117 return HANDLED; 1118 } 1119 1120 @Override exit()1121 public void exit() { 1122 updateConnectModeState(mRole, WifiManager.WIFI_STATE_DISABLED, 1123 WifiManager.WIFI_STATE_DISABLING); 1124 1125 if (mClientModeImpl == null) { 1126 Log.w(getTag(), "ConnectModeState.exit(): mClientModeImpl is already null?!"); 1127 } else { 1128 Log.d(getTag(), "Stopping ClientModeImpl"); 1129 mClientModeImpl.stop(); 1130 mGraveyard.inter(mClientModeImpl); 1131 mClientModeImpl = null; 1132 } 1133 1134 mConnectRoleChangeInfoToSetOnTransition = null; 1135 } 1136 } 1137 } 1138 1139 /** Called by a ClientModeImpl owned by this CMM informing it has fully stopped. */ onClientModeImplQuit()1140 public void onClientModeImplQuit() { 1141 cleanupOnQuitIfApplicable(); 1142 } 1143 1144 /** 1145 * Only clean up this CMM once the CMM and all associated ClientModeImpls have been stopped. 1146 * This is necessary because ClientModeImpl sends broadcasts during stop, and the role must 1147 * remain primary for {@link ClientModeManagerBroadcastQueue} to send them out. 1148 */ cleanupOnQuitIfApplicable()1149 private void cleanupOnQuitIfApplicable() { 1150 if (mIsStopped && mGraveyard.hasAllClientModeImplsQuit()) { 1151 mPreviousRole = mRole; 1152 mLastRoleChangeSinceBootMs = mClock.getElapsedSinceBootMillis(); 1153 mRole = null; 1154 // only call onStopped() after role has been reset to null since ActiveModeWarden 1155 // expects the CMM to be fully stopped before onStopped(). 1156 mModeListener.onStopped(ConcreteClientModeManager.this); 1157 1158 // reset to false so that onStopped() won't be triggered again. 1159 mIsStopped = false; 1160 } 1161 } 1162 takeBugReportInterfaceFailureIfNeeded(String bugTitle)1163 private void takeBugReportInterfaceFailureIfNeeded(String bugTitle) { 1164 if (mWifiInjector.getDeviceConfigFacade().isInterfaceFailureBugreportEnabled()) { 1165 mWifiInjector.getWifiDiagnostics().takeBugReport(bugTitle, bugTitle); 1166 } 1167 } 1168 1169 @NonNull getClientMode()1170 private ClientMode getClientMode() { 1171 if (mClientModeImpl != null) { 1172 return mClientModeImpl; 1173 } 1174 if (mScanOnlyModeImpl != null) { 1175 return mScanOnlyModeImpl; 1176 } 1177 return mDefaultClientModeManager; 1178 } 1179 1180 /* 1181 * Note: These are simple wrappers over methods to {@link ClientModeImpl}. 1182 */ 1183 1184 @Override connectNetwork(NetworkUpdateResult result, ActionListenerWrapper wrapper, int callingUid, @NonNull String packageName)1185 public void connectNetwork(NetworkUpdateResult result, ActionListenerWrapper wrapper, 1186 int callingUid, @NonNull String packageName) { 1187 getClientMode().connectNetwork(result, wrapper, callingUid, packageName); 1188 } 1189 1190 @Override saveNetwork(NetworkUpdateResult result, ActionListenerWrapper wrapper, int callingUid, @NonNull String packageName)1191 public void saveNetwork(NetworkUpdateResult result, ActionListenerWrapper wrapper, 1192 int callingUid, @NonNull String packageName) { 1193 getClientMode().saveNetwork(result, wrapper, callingUid, packageName); 1194 } 1195 1196 @Override disconnect()1197 public void disconnect() { 1198 getClientMode().disconnect(); 1199 } 1200 1201 @Override reconnect(WorkSource ws)1202 public void reconnect(WorkSource ws) { 1203 getClientMode().reconnect(ws); 1204 } 1205 1206 @Override reassociate()1207 public void reassociate() { 1208 getClientMode().reassociate(); 1209 } 1210 1211 @Override startConnectToNetwork(int networkId, int uid, String bssid)1212 public void startConnectToNetwork(int networkId, int uid, String bssid) { 1213 getClientMode().startConnectToNetwork(networkId, uid, bssid); 1214 } 1215 1216 @Override startRoamToNetwork(int networkId, String bssid)1217 public void startRoamToNetwork(int networkId, String bssid) { 1218 getClientMode().startRoamToNetwork(networkId, bssid); 1219 } 1220 1221 @Override setWifiConnectedNetworkScorer( IBinder binder, IWifiConnectedNetworkScorer scorer)1222 public boolean setWifiConnectedNetworkScorer( 1223 IBinder binder, IWifiConnectedNetworkScorer scorer) { 1224 return getClientMode().setWifiConnectedNetworkScorer(binder, scorer); 1225 } 1226 1227 @Override clearWifiConnectedNetworkScorer()1228 public void clearWifiConnectedNetworkScorer() { 1229 getClientMode().clearWifiConnectedNetworkScorer(); 1230 } 1231 1232 @Override resetSimAuthNetworks(@lientModeImpl.ResetSimReason int resetReason)1233 public void resetSimAuthNetworks(@ClientModeImpl.ResetSimReason int resetReason) { 1234 getClientMode().resetSimAuthNetworks(resetReason); 1235 } 1236 1237 @Override onBluetoothConnectionStateChanged()1238 public void onBluetoothConnectionStateChanged() { 1239 getClientMode().onBluetoothConnectionStateChanged(); 1240 } 1241 1242 @Override syncRequestConnectionInfo()1243 public WifiInfo syncRequestConnectionInfo() { 1244 return getClientMode().syncRequestConnectionInfo(); 1245 } 1246 1247 @Override syncQueryPasspointIcon(long bssid, String fileName)1248 public boolean syncQueryPasspointIcon(long bssid, String fileName) { 1249 return getClientMode().syncQueryPasspointIcon(bssid, fileName); 1250 } 1251 1252 @Override syncGetCurrentNetwork()1253 public Network syncGetCurrentNetwork() { 1254 return getClientMode().syncGetCurrentNetwork(); 1255 } 1256 1257 @Override syncGetDhcpResultsParcelable()1258 public DhcpResultsParcelable syncGetDhcpResultsParcelable() { 1259 return getClientMode().syncGetDhcpResultsParcelable(); 1260 } 1261 1262 @Override getSupportedFeatures()1263 public long getSupportedFeatures() { 1264 return getClientMode().getSupportedFeatures(); 1265 } 1266 1267 @Override syncStartSubscriptionProvisioning(int callingUid, OsuProvider provider, IProvisioningCallback callback)1268 public boolean syncStartSubscriptionProvisioning(int callingUid, OsuProvider provider, 1269 IProvisioningCallback callback) { 1270 return getClientMode().syncStartSubscriptionProvisioning( 1271 callingUid, provider, callback); 1272 } 1273 1274 @Override isWifiStandardSupported(@ifiAnnotations.WifiStandard int standard)1275 public boolean isWifiStandardSupported(@WifiAnnotations.WifiStandard int standard) { 1276 return getClientMode().isWifiStandardSupported(standard); 1277 } 1278 1279 @Override enableTdls(String remoteMacAddress, boolean enable)1280 public void enableTdls(String remoteMacAddress, boolean enable) { 1281 getClientMode().enableTdls(remoteMacAddress, enable); 1282 } 1283 1284 @Override dumpIpClient(FileDescriptor fd, PrintWriter pw, String[] args)1285 public void dumpIpClient(FileDescriptor fd, PrintWriter pw, String[] args) { 1286 getClientMode().dumpIpClient(fd, pw, args); 1287 } 1288 1289 @Override dumpWifiScoreReport(FileDescriptor fd, PrintWriter pw, String[] args)1290 public void dumpWifiScoreReport(FileDescriptor fd, PrintWriter pw, String[] args) { 1291 getClientMode().dumpWifiScoreReport(fd, pw, args); 1292 } 1293 1294 @Override enableVerboseLogging(boolean verbose)1295 public void enableVerboseLogging(boolean verbose) { 1296 mVerboseLoggingEnabled = verbose; 1297 getClientMode().enableVerboseLogging(verbose); 1298 } 1299 1300 @Override getFactoryMacAddress()1301 public String getFactoryMacAddress() { 1302 return getClientMode().getFactoryMacAddress(); 1303 } 1304 1305 @Override getConnectedWifiConfiguration()1306 public WifiConfiguration getConnectedWifiConfiguration() { 1307 return getClientMode().getConnectedWifiConfiguration(); 1308 } 1309 1310 @Override getConnectingWifiConfiguration()1311 public WifiConfiguration getConnectingWifiConfiguration() { 1312 return getClientMode().getConnectingWifiConfiguration(); 1313 } 1314 1315 @Override getConnectedBssid()1316 public String getConnectedBssid() { 1317 return getClientMode().getConnectedBssid(); 1318 } 1319 1320 @Override getConnectingBssid()1321 public String getConnectingBssid() { 1322 return getClientMode().getConnectingBssid(); 1323 } 1324 1325 @Override getWifiLinkLayerStats()1326 public WifiLinkLayerStats getWifiLinkLayerStats() { 1327 return getClientMode().getWifiLinkLayerStats(); 1328 } 1329 1330 @Override setPowerSave(@owerSaveClientType int client, boolean ps)1331 public boolean setPowerSave(@PowerSaveClientType int client, boolean ps) { 1332 return getClientMode().setPowerSave(client, ps); 1333 } 1334 1335 @Override enablePowerSave()1336 public boolean enablePowerSave() { 1337 return getClientMode().enablePowerSave(); 1338 } 1339 1340 @Override setLowLatencyMode(boolean enabled)1341 public boolean setLowLatencyMode(boolean enabled) { 1342 return getClientMode().setLowLatencyMode(enabled); 1343 } 1344 1345 @Override getMcastLockManagerFilterController()1346 public WifiMulticastLockManager.FilterController getMcastLockManagerFilterController() { 1347 return getClientMode().getMcastLockManagerFilterController(); 1348 } 1349 1350 @Override isConnected()1351 public boolean isConnected() { 1352 return getClientMode().isConnected(); 1353 } 1354 1355 @Override isConnecting()1356 public boolean isConnecting() { 1357 return getClientMode().isConnecting(); 1358 } 1359 1360 @Override isRoaming()1361 public boolean isRoaming() { 1362 return getClientMode().isRoaming(); 1363 } 1364 1365 @Override isDisconnected()1366 public boolean isDisconnected() { 1367 return getClientMode().isDisconnected(); 1368 } 1369 1370 @Override isSupplicantTransientState()1371 public boolean isSupplicantTransientState() { 1372 return getClientMode().isSupplicantTransientState(); 1373 } 1374 1375 @Override onCellularConnectivityChanged(@ifiDataStall.CellularDataStatusCode int status)1376 public void onCellularConnectivityChanged(@WifiDataStall.CellularDataStatusCode int status) { 1377 getClientMode().onCellularConnectivityChanged(status); 1378 } 1379 1380 @Override probeLink(LinkProbeCallback callback, int mcs)1381 public void probeLink(LinkProbeCallback callback, int mcs) { 1382 getClientMode().probeLink(callback, mcs); 1383 } 1384 1385 @Override sendMessageToClientModeImpl(Message msg)1386 public void sendMessageToClientModeImpl(Message msg) { 1387 getClientMode().sendMessageToClientModeImpl(msg); 1388 } 1389 1390 @Override getId()1391 public long getId() { 1392 return mId; 1393 } 1394 1395 @Override setMboCellularDataStatus(boolean available)1396 public void setMboCellularDataStatus(boolean available) { 1397 getClientMode().setMboCellularDataStatus(available); 1398 } 1399 1400 @Override getRoamingCapabilities()1401 public WifiNative.RoamingCapabilities getRoamingCapabilities() { 1402 return getClientMode().getRoamingCapabilities(); 1403 } 1404 1405 @Override configureRoaming(WifiNative.RoamingConfig config)1406 public boolean configureRoaming(WifiNative.RoamingConfig config) { 1407 return getClientMode().configureRoaming(config); 1408 } 1409 1410 @Override enableRoaming(boolean enabled)1411 public boolean enableRoaming(boolean enabled) { 1412 return getClientMode().enableRoaming(enabled); 1413 } 1414 1415 @Override setCountryCode(String countryCode)1416 public boolean setCountryCode(String countryCode) { 1417 return getClientMode().setCountryCode(countryCode); 1418 } 1419 1420 @Override getTxPktFates()1421 public List<TxFateReport> getTxPktFates() { 1422 return getClientMode().getTxPktFates(); 1423 } 1424 1425 @Override getRxPktFates()1426 public List<RxFateReport> getRxPktFates() { 1427 return getClientMode().getRxPktFates(); 1428 } 1429 1430 @Override getDeviceWiphyCapabilities()1431 public DeviceWiphyCapabilities getDeviceWiphyCapabilities() { 1432 return getClientMode().getDeviceWiphyCapabilities(); 1433 } 1434 1435 @Override requestAnqp(String bssid, Set<Integer> anqpIds, Set<Integer> hs20Subtypes)1436 public boolean requestAnqp(String bssid, Set<Integer> anqpIds, Set<Integer> hs20Subtypes) { 1437 return getClientMode().requestAnqp(bssid, anqpIds, hs20Subtypes); 1438 } 1439 1440 @Override requestVenueUrlAnqp(String bssid)1441 public boolean requestVenueUrlAnqp(String bssid) { 1442 return getClientMode().requestVenueUrlAnqp(bssid); 1443 } 1444 1445 @Override requestIcon(String bssid, String fileName)1446 public boolean requestIcon(String bssid, String fileName) { 1447 return getClientMode().requestIcon(bssid, fileName); 1448 } 1449 1450 @Override setShouldReduceNetworkScore(boolean shouldReduceNetworkScore)1451 public void setShouldReduceNetworkScore(boolean shouldReduceNetworkScore) { 1452 mShouldReduceNetworkScore = shouldReduceNetworkScore; 1453 getClientMode().setShouldReduceNetworkScore(shouldReduceNetworkScore); 1454 } 1455 1456 @Override toString()1457 public String toString() { 1458 return "ConcreteClientModeManager{id=" + getId() 1459 + " iface=" + getInterfaceName() 1460 + " role=" + getRole() 1461 + "}"; 1462 } 1463 1464 @Override updateCapabilities()1465 public void updateCapabilities() { 1466 getClientMode().updateCapabilities(); 1467 } 1468 } 1469