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